summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/cpython/coreconfig.h10
-rw-r--r--Include/internal/pycore_coreconfig.h26
-rw-r--r--Include/internal/pycore_pathconfig.h14
-rw-r--r--Modules/main.c1863
-rw-r--r--Python/coreconfig.c975
5 files changed, 1473 insertions, 1415 deletions
diff --git a/Include/cpython/coreconfig.h b/Include/cpython/coreconfig.h
index 4985bf3..8109d4a 100644
--- a/Include/cpython/coreconfig.h
+++ b/Include/cpython/coreconfig.h
@@ -5,6 +5,16 @@
extern "C" {
#endif
+/* _PyArgv */
+
+typedef struct {
+ int argc;
+ int use_bytes_argv;
+ char **bytes_argv;
+ wchar_t **wchar_argv;
+} _PyArgv;
+
+
/* _PyInitError */
typedef struct {
diff --git a/Include/internal/pycore_coreconfig.h b/Include/internal/pycore_coreconfig.h
index b906ac4..ebb0a9e 100644
--- a/Include/internal/pycore_coreconfig.h
+++ b/Include/internal/pycore_coreconfig.h
@@ -8,6 +8,29 @@ extern "C" {
# error "this header requires Py_BUILD_CORE or Py_BUILD_CORE_BUILTIN defined"
#endif
+/* _Py_wstrlist */
+
+PyAPI_FUNC(void) _Py_wstrlist_clear(
+ int len,
+ wchar_t **list);
+PyAPI_FUNC(wchar_t**) _Py_wstrlist_copy(
+ int len,
+ wchar_t * const *list);
+PyAPI_FUNC(_PyInitError) _Py_wstrlist_append(
+ int *len,
+ wchar_t ***list,
+ const wchar_t *str);
+PyAPI_FUNC(PyObject*) _Py_wstrlist_as_pylist(
+ int len,
+ wchar_t **list);
+
+/* Py_GetArgcArgv() helpers */
+
+PyAPI_FUNC(void) _Py_ClearArgcArgv(void);
+PyAPI_FUNC(int) _Py_SetArgcArgv(int argc, wchar_t * const *argv);
+
+/* _PyCoreConfig */
+
PyAPI_FUNC(_PyInitError) _PyCoreConfig_Read(_PyCoreConfig *config);
PyAPI_FUNC(void) _PyCoreConfig_Clear(_PyCoreConfig *);
PyAPI_FUNC(int) _PyCoreConfig_Copy(
@@ -26,6 +49,9 @@ PyAPI_FUNC(int) _PyCoreConfig_GetEnvDup(
wchar_t **dest,
wchar_t *wname,
char *name);
+PyAPI_FUNC(_PyInitError) _PyCoreConfig_ReadFromArgv(_PyCoreConfig *config,
+ const _PyArgv *args);
+PyAPI_FUNC(void) _PyCoreConfig_Write(const _PyCoreConfig *config);
#ifdef __cplusplus
}
diff --git a/Include/internal/pycore_pathconfig.h b/Include/internal/pycore_pathconfig.h
index c073152..fb6b1d7 100644
--- a/Include/internal/pycore_pathconfig.h
+++ b/Include/internal/pycore_pathconfig.h
@@ -8,20 +8,6 @@ extern "C" {
# error "this header requires Py_BUILD_CORE or Py_BUILD_CORE_BUILTIN define"
#endif
-PyAPI_FUNC(void) _Py_wstrlist_clear(
- int len,
- wchar_t **list);
-PyAPI_FUNC(wchar_t**) _Py_wstrlist_copy(
- int len,
- wchar_t **list);
-PyAPI_FUNC(_PyInitError) _Py_wstrlist_append(
- int *len,
- wchar_t ***list,
- const wchar_t *str);
-PyAPI_FUNC(PyObject*) _Py_wstrlist_as_pylist(
- int len,
- wchar_t **list);
-
typedef struct _PyPathConfig {
/* Full path to the Python program */
wchar_t *program_full_path;
diff --git a/Modules/main.c b/Modules/main.c
index e7d75a7..fdeaf1d 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -1,46 +1,27 @@
/* Python interpreter main program */
#include "Python.h"
-#include "osdefs.h"
#include "pycore_coreconfig.h"
-#include "pycore_getopt.h"
-#include "pycore_pathconfig.h"
#include "pycore_pylifecycle.h"
#include "pycore_pymem.h"
#include "pycore_pystate.h"
-#include <locale.h>
+#ifdef __FreeBSD__
+# include <fenv.h> /* fedisableexcept() */
+#endif
+
+/* Includes for exit_sigint() */
+#include <stdio.h> /* perror() */
#ifdef HAVE_SIGNAL_H
-#include <signal.h>
+# include <signal.h> /* SIGINT */
#endif
-#include <stdio.h>
#if defined(HAVE_GETPID) && defined(HAVE_UNISTD_H)
-#include <unistd.h>
-#endif
-
-#if defined(MS_WINDOWS) || defined(__CYGWIN__)
-# include <windows.h>
-# ifdef HAVE_IO_H
-# include <io.h>
-# endif
-# ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-# endif
+# include <unistd.h> /* getpid() */
#endif
-
#ifdef _MSC_VER
-# include <crtdbg.h>
-#endif
-
-#ifdef __FreeBSD__
-# include <fenv.h>
-#endif
-
-#if defined(MS_WINDOWS)
-# define PYTHONHOMEHELP "<prefix>\\python{major}{minor}"
-#else
-# define PYTHONHOMEHELP "<prefix>/lib/pythonX.X"
+# include <crtdbg.h> /* STATUS_CONTROL_C_EXIT */
#endif
+/* End of includes for exit_sigint() */
#define COPYRIGHT \
"Type \"help\", \"copyright\", \"credits\" or \"license\" " \
@@ -50,371 +31,264 @@
extern "C" {
#endif
-#define DECODE_LOCALE_ERR(NAME, LEN) \
- (((LEN) == -2) \
- ? _Py_INIT_USER_ERR("cannot decode " NAME) \
- : _Py_INIT_NO_MEMORY())
-
+/* --- PyMainInterpreter ------------------------------------------ */
-#ifdef MS_WINDOWS
-#define WCSTOK wcstok_s
-#else
-#define WCSTOK wcstok
-#endif
+void
+_PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *config)
+{
+ Py_CLEAR(config->argv);
+ Py_CLEAR(config->executable);
+ Py_CLEAR(config->prefix);
+ Py_CLEAR(config->base_prefix);
+ Py_CLEAR(config->exec_prefix);
+ Py_CLEAR(config->base_exec_prefix);
+ Py_CLEAR(config->warnoptions);
+ Py_CLEAR(config->xoptions);
+ Py_CLEAR(config->module_search_path);
+ Py_CLEAR(config->pycache_prefix);
+}
-/* For Py_GetArgcArgv(); set by main() */
-static wchar_t **orig_argv = NULL;
-static int orig_argc = 0;
-
-/* command line options */
-#define BASE_OPTS L"bBc:dEhiIJm:OqRsStuvVW:xX:?"
-
-#define PROGRAM_OPTS BASE_OPTS
-
-static const _PyOS_LongOption longoptions[] = {
- {L"check-hash-based-pycs", 1, 0},
- {NULL, 0, 0},
-};
-
-/* Short usage message (with %s for argv0) */
-static const char usage_line[] =
-"usage: %ls [option] ... [-c cmd | -m mod | file | -] [arg] ...\n";
-
-/* Long usage message, split into parts < 512 bytes */
-static const char usage_1[] = "\
-Options and arguments (and corresponding environment variables):\n\
--b : issue warnings about str(bytes_instance), str(bytearray_instance)\n\
- and comparing bytes/bytearray with str. (-bb: issue errors)\n\
--B : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x\n\
--c cmd : program passed in as string (terminates option list)\n\
--d : debug output from parser; also PYTHONDEBUG=x\n\
--E : ignore PYTHON* environment variables (such as PYTHONPATH)\n\
--h : print this help message and exit (also --help)\n\
-";
-static const char usage_2[] = "\
--i : inspect interactively after running script; forces a prompt even\n\
- if stdin does not appear to be a terminal; also PYTHONINSPECT=x\n\
--I : isolate Python from the user's environment (implies -E and -s)\n\
--m mod : run library module as a script (terminates option list)\n\
--O : remove assert and __debug__-dependent statements; add .opt-1 before\n\
- .pyc extension; also PYTHONOPTIMIZE=x\n\
--OO : do -O changes and also discard docstrings; add .opt-2 before\n\
- .pyc extension\n\
--q : don't print version and copyright messages on interactive startup\n\
--s : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\
--S : don't imply 'import site' on initialization\n\
-";
-static const char usage_3[] = "\
--u : force the stdout and stderr streams to be unbuffered;\n\
- this option has no effect on stdin; also PYTHONUNBUFFERED=x\n\
--v : verbose (trace import statements); also PYTHONVERBOSE=x\n\
- can be supplied multiple times to increase verbosity\n\
--V : print the Python version number and exit (also --version)\n\
- when given twice, print more information about the build\n\
--W arg : warning control; arg is action:message:category:module:lineno\n\
- also PYTHONWARNINGS=arg\n\
--x : skip first line of source, allowing use of non-Unix forms of #!cmd\n\
--X opt : set implementation-specific option\n\
---check-hash-based-pycs always|default|never:\n\
- control how Python invalidates hash-based .pyc files\n\
-";
-static const char usage_4[] = "\
-file : program read from script file\n\
-- : program read from stdin (default; interactive mode if a tty)\n\
-arg ...: arguments passed to program in sys.argv[1:]\n\n\
-Other environment variables:\n\
-PYTHONSTARTUP: file executed on interactive startup (no default)\n\
-PYTHONPATH : '%lc'-separated list of directories prefixed to the\n\
- default module search path. The result is sys.path.\n\
-";
-static const char usage_5[] =
-"PYTHONHOME : alternate <prefix> directory (or <prefix>%lc<exec_prefix>).\n"
-" The default module search path uses %s.\n"
-"PYTHONCASEOK : ignore case in 'import' statements (Windows).\n"
-"PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n"
-"PYTHONFAULTHANDLER: dump the Python traceback on fatal errors.\n";
-static const char usage_6[] =
-"PYTHONHASHSEED: if this variable is set to 'random', a random value is used\n"
-" to seed the hashes of str, bytes and datetime objects. It can also be\n"
-" set to an integer in the range [0,4294967295] to get hash values with a\n"
-" predictable seed.\n"
-"PYTHONMALLOC: set the Python memory allocators and/or install debug hooks\n"
-" on Python memory allocators. Use PYTHONMALLOC=debug to install debug\n"
-" hooks.\n"
-"PYTHONCOERCECLOCALE: if this variable is set to 0, it disables the locale\n"
-" coercion behavior. Use PYTHONCOERCECLOCALE=warn to request display of\n"
-" locale coercion and locale compatibility warnings on stderr.\n"
-"PYTHONBREAKPOINT: if this variable is set to 0, it disables the default\n"
-" debugger. It can be set to the callable of your debugger of choice.\n"
-"PYTHONDEVMODE: enable the development mode.\n"
-"PYTHONPYCACHEPREFIX: root directory for bytecode cache (pyc) files.\n";
-static void
-pymain_usage(int error, const wchar_t* program)
+static int
+mainconfig_add_xoption(PyObject *opts, const wchar_t *s)
{
- FILE *f = error ? stderr : stdout;
+ PyObject *name, *value;
- fprintf(f, usage_line, program);
- if (error)
- fprintf(f, "Try `python -h' for more information.\n");
+ const wchar_t *name_end = wcschr(s, L'=');
+ if (!name_end) {
+ name = PyUnicode_FromWideChar(s, -1);
+ value = Py_True;
+ Py_INCREF(value);
+ }
else {
- fputs(usage_1, f);
- fputs(usage_2, f);
- fputs(usage_3, f);
- fprintf(f, usage_4, (wint_t)DELIM);
- fprintf(f, usage_5, (wint_t)DELIM, PYTHONHOMEHELP);
- fputs(usage_6, f);
+ name = PyUnicode_FromWideChar(s, name_end - s);
+ value = PyUnicode_FromWideChar(name_end + 1, -1);
}
-}
-
-
-static void
-pymain_run_interactive_hook(void)
-{
- PyObject *sys, *hook, *result;
- sys = PyImport_ImportModule("sys");
- if (sys == NULL) {
+ if (name == NULL || value == NULL) {
goto error;
}
-
- hook = PyObject_GetAttrString(sys, "__interactivehook__");
- Py_DECREF(sys);
- if (hook == NULL) {
- PyErr_Clear();
- return;
- }
-
- result = _PyObject_CallNoArg(hook);
- Py_DECREF(hook);
- if (result == NULL) {
+ if (PyDict_SetItem(opts, name, value) < 0) {
goto error;
}
- Py_DECREF(result);
-
- return;
+ Py_DECREF(name);
+ Py_DECREF(value);
+ return 0;
error:
- PySys_WriteStderr("Failed calling sys.__interactivehook__\n");
- PyErr_Print();
+ Py_XDECREF(name);
+ Py_XDECREF(value);
+ return -1;
}
-static int
-pymain_run_module(const wchar_t *modname, int set_argv0)
+static PyObject*
+mainconfig_create_xoptions_dict(const _PyCoreConfig *config)
{
- PyObject *module, *runpy, *runmodule, *runargs, *result;
- runpy = PyImport_ImportModule("runpy");
- if (runpy == NULL) {
- fprintf(stderr, "Could not import runpy module\n");
- PyErr_Print();
- return -1;
- }
- runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main");
- if (runmodule == NULL) {
- fprintf(stderr, "Could not access runpy._run_module_as_main\n");
- PyErr_Print();
- Py_DECREF(runpy);
- return -1;
- }
- module = PyUnicode_FromWideChar(modname, wcslen(modname));
- if (module == NULL) {
- fprintf(stderr, "Could not convert module name to unicode\n");
- PyErr_Print();
- Py_DECREF(runpy);
- Py_DECREF(runmodule);
- return -1;
- }
- runargs = Py_BuildValue("(Oi)", module, set_argv0);
- if (runargs == NULL) {
- fprintf(stderr,
- "Could not create arguments for runpy._run_module_as_main\n");
- PyErr_Print();
- Py_DECREF(runpy);
- Py_DECREF(runmodule);
- Py_DECREF(module);
- return -1;
- }
- result = PyObject_Call(runmodule, runargs, NULL);
- if (result == NULL) {
- PyErr_Print();
+ int nxoption = config->nxoption;
+ wchar_t **xoptions = config->xoptions;
+ PyObject *dict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
}
- Py_DECREF(runpy);
- Py_DECREF(runmodule);
- Py_DECREF(module);
- Py_DECREF(runargs);
- if (result == NULL) {
- return -1;
+
+ for (int i=0; i < nxoption; i++) {
+ wchar_t *option = xoptions[i];
+ if (mainconfig_add_xoption(dict, option) < 0) {
+ Py_DECREF(dict);
+ return NULL;
+ }
}
- Py_DECREF(result);
- return 0;
+
+ return dict;
}
-static PyObject *
-pymain_get_importer(const wchar_t *filename)
-{
- PyObject *sys_path0 = NULL, *importer;
- sys_path0 = PyUnicode_FromWideChar(filename, wcslen(filename));
- if (sys_path0 == NULL) {
- goto error;
+static PyObject*
+mainconfig_copy_attr(PyObject *obj)
+{
+ if (PyUnicode_Check(obj)) {
+ Py_INCREF(obj);
+ return obj;
}
-
- importer = PyImport_GetImporter(sys_path0);
- if (importer == NULL) {
- goto error;
+ else if (PyList_Check(obj)) {
+ return PyList_GetSlice(obj, 0, Py_SIZE(obj));
}
-
- if (importer == Py_None) {
- Py_DECREF(sys_path0);
- Py_DECREF(importer);
+ else if (PyDict_Check(obj)) {
+ /* The dict type is used for xoptions. Make the assumption that keys
+ and values are immutables */
+ return PyDict_Copy(obj);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "cannot copy config attribute of type %.200s",
+ Py_TYPE(obj)->tp_name);
return NULL;
}
-
- Py_DECREF(importer);
- return sys_path0;
-
-error:
- Py_XDECREF(sys_path0);
- PySys_WriteStderr("Failed checking if argv[0] is an import path entry\n");
- PyErr_Print();
- return NULL;
}
-static int
-pymain_run_command(wchar_t *command, PyCompilerFlags *cf)
+int
+_PyMainInterpreterConfig_Copy(_PyMainInterpreterConfig *config,
+ const _PyMainInterpreterConfig *config2)
{
- PyObject *unicode, *bytes;
- int ret;
+ _PyMainInterpreterConfig_Clear(config);
- unicode = PyUnicode_FromWideChar(command, -1);
- if (unicode == NULL) {
- goto error;
- }
+#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
+#define COPY_OBJ_ATTR(ATTR) \
+ do { \
+ if (config2->ATTR != NULL) { \
+ config->ATTR = mainconfig_copy_attr(config2->ATTR); \
+ if (config->ATTR == NULL) { \
+ return -1; \
+ } \
+ } \
+ } while (0)
- bytes = PyUnicode_AsUTF8String(unicode);
- Py_DECREF(unicode);
- if (bytes == NULL) {
- goto error;
- }
+ COPY_ATTR(install_signal_handlers);
+ COPY_OBJ_ATTR(argv);
+ COPY_OBJ_ATTR(executable);
+ COPY_OBJ_ATTR(prefix);
+ COPY_OBJ_ATTR(base_prefix);
+ COPY_OBJ_ATTR(exec_prefix);
+ COPY_OBJ_ATTR(base_exec_prefix);
+ COPY_OBJ_ATTR(warnoptions);
+ COPY_OBJ_ATTR(xoptions);
+ COPY_OBJ_ATTR(module_search_path);
+ COPY_OBJ_ATTR(pycache_prefix);
+#undef COPY_ATTR
+#undef COPY_OBJ_ATTR
+ return 0;
+}
- ret = PyRun_SimpleStringFlags(PyBytes_AsString(bytes), cf);
- Py_DECREF(bytes);
- return (ret != 0);
-error:
- PySys_WriteStderr("Unable to decode the command from the command line:\n");
- PyErr_Print();
- return 1;
-}
+PyObject*
+_PyMainInterpreterConfig_AsDict(const _PyMainInterpreterConfig *config)
+{
+ PyObject *dict, *obj;
+ int res;
+ dict = PyDict_New();
+ if (dict == NULL) {
+ return NULL;
+ }
-/* Main program */
+#define SET_ITEM_INT(ATTR) \
+ do { \
+ obj = PyLong_FromLong(config->ATTR); \
+ if (obj == NULL) { \
+ goto fail; \
+ } \
+ res = PyDict_SetItemString(dict, #ATTR, obj); \
+ Py_DECREF(obj); \
+ if (res < 0) { \
+ goto fail; \
+ } \
+ } while (0)
-typedef struct {
- int argc;
- int use_bytes_argv;
- char **bytes_argv;
- wchar_t **wchar_argv;
-} _PyArgv;
+#define SET_ITEM_OBJ(ATTR) \
+ do { \
+ obj = config->ATTR; \
+ if (obj == NULL) { \
+ obj = Py_None; \
+ } \
+ res = PyDict_SetItemString(dict, #ATTR, obj); \
+ if (res < 0) { \
+ goto fail; \
+ } \
+ } while (0)
-typedef struct {
- const _PyArgv *args;
- wchar_t **argv;
- int nwarnoption; /* Number of -W command line options */
- wchar_t **warnoptions; /* Command line -W options */
- int nenv_warnoption; /* Number of PYTHONWARNINGS environment variables */
- wchar_t **env_warnoptions; /* PYTHONWARNINGS environment variables */
- int print_help; /* -h, -? options */
- int print_version; /* -V option */
-} _PyCmdline;
+ SET_ITEM_INT(install_signal_handlers);
+ SET_ITEM_OBJ(argv);
+ SET_ITEM_OBJ(executable);
+ SET_ITEM_OBJ(prefix);
+ SET_ITEM_OBJ(base_prefix);
+ SET_ITEM_OBJ(exec_prefix);
+ SET_ITEM_OBJ(base_exec_prefix);
+ SET_ITEM_OBJ(warnoptions);
+ SET_ITEM_OBJ(xoptions);
+ SET_ITEM_OBJ(module_search_path);
+ SET_ITEM_OBJ(pycache_prefix);
+ return dict;
+fail:
+ Py_DECREF(dict);
+ return NULL;
-/* Non-zero if filename, command (-c) or module (-m) is set
- on the command line */
-#define RUN_CODE(config) \
- (config->run_command != NULL || config->run_filename != NULL \
- || config->run_module != NULL)
+#undef SET_ITEM_OBJ
+}
-static _PyInitError
-pymain_init_cmdline_argv(_PyCoreConfig *config, _PyCmdline *cmdline)
+_PyInitError
+_PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config,
+ const _PyCoreConfig *config)
{
- assert(cmdline->argv == NULL);
-
- const _PyArgv *args = cmdline->args;
+ if (main_config->install_signal_handlers < 0) {
+ main_config->install_signal_handlers = config->install_signal_handlers;
+ }
- if (args->use_bytes_argv) {
- /* +1 for a the NULL terminator */
- size_t size = sizeof(wchar_t*) * (args->argc + 1);
- wchar_t** argv = (wchar_t **)PyMem_RawMalloc(size);
- if (argv == NULL) {
+ if (main_config->xoptions == NULL) {
+ main_config->xoptions = mainconfig_create_xoptions_dict(config);
+ if (main_config->xoptions == NULL) {
return _Py_INIT_NO_MEMORY();
}
-
- for (int i = 0; i < args->argc; i++) {
- size_t len;
- wchar_t *arg = Py_DecodeLocale(args->bytes_argv[i], &len);
- if (arg == NULL) {
- _Py_wstrlist_clear(i, argv);
- return DECODE_LOCALE_ERR("command line arguments",
- (Py_ssize_t)len);
- }
- argv[i] = arg;
- }
- argv[args->argc] = NULL;
-
- cmdline->argv = argv;
- }
- else {
- cmdline->argv = args->wchar_argv;
}
- wchar_t *program;
- if (args->argc >= 1 && cmdline->argv != NULL) {
- program = cmdline->argv[0];
- }
- else {
- program = L"";
- }
- config->program = _PyMem_RawWcsdup(program);
- if (config->program == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
-
- return _Py_INIT_OK();
-}
+#define COPY_WSTR(ATTR) \
+ do { \
+ if (main_config->ATTR == NULL && config->ATTR != NULL) { \
+ main_config->ATTR = PyUnicode_FromWideChar(config->ATTR, -1); \
+ if (main_config->ATTR == NULL) { \
+ return _Py_INIT_NO_MEMORY(); \
+ } \
+ } \
+ } while (0)
+#define COPY_WSTRLIST(ATTR, LEN, LIST) \
+ do { \
+ if (ATTR == NULL) { \
+ ATTR = _Py_wstrlist_as_pylist(LEN, LIST); \
+ if (ATTR == NULL) { \
+ return _Py_INIT_NO_MEMORY(); \
+ } \
+ } \
+ } while (0)
+ COPY_WSTRLIST(main_config->warnoptions,
+ config->nwarnoption, config->warnoptions);
+ if (config->argc >= 0) {
+ COPY_WSTRLIST(main_config->argv,
+ config->argc, config->argv);
+ }
-static void
-pymain_clear_cmdline(_PyCmdline *cmdline)
-{
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+ if (config->_install_importlib) {
+ COPY_WSTR(executable);
+ COPY_WSTR(prefix);
+ COPY_WSTR(base_prefix);
+ COPY_WSTR(exec_prefix);
+ COPY_WSTR(base_exec_prefix);
- _Py_wstrlist_clear(cmdline->nwarnoption, cmdline->warnoptions);
- cmdline->nwarnoption = 0;
- cmdline->warnoptions = NULL;
+ COPY_WSTRLIST(main_config->module_search_path,
+ config->nmodule_search_path, config->module_search_paths);
- _Py_wstrlist_clear(cmdline->nenv_warnoption, cmdline->env_warnoptions);
- cmdline->nenv_warnoption = 0;
- cmdline->env_warnoptions = NULL;
+ if (config->pycache_prefix != NULL) {
+ COPY_WSTR(pycache_prefix);
+ } else {
+ main_config->pycache_prefix = NULL;
+ }
- if (cmdline->args->use_bytes_argv && cmdline->argv != NULL) {
- _Py_wstrlist_clear(cmdline->args->argc, cmdline->argv);
}
- cmdline->argv = NULL;
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+ return _Py_INIT_OK();
+#undef COPY_WSTR
+#undef COPY_WSTRLIST
}
+/* --- pymain_init() ---------------------------------------------- */
+
static void
-pymain_clear_config(_PyCoreConfig *config)
+config_clear(_PyCoreConfig *config)
{
- /* Clear core config with the memory allocator
- used by pymain_read_conf() */
PyMemAllocatorEx old_alloc;
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
@@ -424,450 +298,102 @@ pymain_clear_config(_PyCoreConfig *config)
}
-static void
-pymain_free(void)
+static _PyInitError
+config_read_write(_PyCoreConfig *config, const _PyArgv *args)
{
- _PyImport_Fini2();
-
- /* Free global variables which cannot be freed in Py_Finalize():
- configuration options set before Py_Initialize() which should
- remain valid after Py_Finalize(), since
- Py_Initialize()-Py_Finalize() can be called multiple times. */
- _PyPathConfig_ClearGlobal();
- _Py_ClearStandardStreamEncoding();
+ _PyInitError err;
- /* Force the allocator used by pymain_read_conf() */
PyMemAllocatorEx old_alloc;
_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- _Py_wstrlist_clear(orig_argc, orig_argv);
- orig_argc = 0;
- orig_argv = NULL;
-
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-
-#ifdef __INSURE__
- /* Insure++ is a memory analysis tool that aids in discovering
- * memory leaks and other memory problems. On Python exit, the
- * interned string dictionaries are flagged as being in use at exit
- * (which it is). Under normal circumstances, this is fine because
- * the memory will be automatically reclaimed by the system. Under
- * memory debugging, it's a huge source of useless noise, so we
- * trade off slower shutdown for less distraction in the memory
- * reports. -baw
- */
- _Py_ReleaseInternedUnicodeStrings();
-#endif /* __INSURE__ */
-}
-
-
-static int
-pymain_sys_path_add_path0(PyInterpreterState *interp, PyObject *path0)
-{
- _Py_IDENTIFIER(path);
- PyObject *sys_path;
- PyObject *sysdict = interp->sysdict;
- if (sysdict != NULL) {
- sys_path = _PyDict_GetItemIdWithError(sysdict, &PyId_path);
- if (sys_path == NULL && PyErr_Occurred()) {
- goto error;
- }
- }
- else {
- sys_path = NULL;
- }
- if (sys_path == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path");
- goto error;
- }
-
- if (PyList_Insert(sys_path, 0, path0)) {
- goto error;
- }
- return 0;
+ _PyCoreConfig_GetGlobalConfig(config);
-error:
- PyErr_Print();
- return -1;
-}
+ err = _PyCoreConfig_ReadFromArgv(config, args);
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-_PyInitError
-_Py_wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
-{
- if (*len == INT_MAX) {
- /* len+1 would overflow */
- return _Py_INIT_NO_MEMORY();
- }
- wchar_t *str2 = _PyMem_RawWcsdup(str);
- if (str2 == NULL) {
- return _Py_INIT_NO_MEMORY();
+ if (_Py_INIT_FAILED(err)) {
+ return err;
}
- size_t size = (*len + 1) * sizeof(list[0]);
- wchar_t **list2 = (wchar_t **)PyMem_RawRealloc(*list, size);
- if (list2 == NULL) {
- PyMem_RawFree(str2);
- return _Py_INIT_NO_MEMORY();
- }
- list2[*len] = str2;
- *list = list2;
- (*len)++;
+ _PyCoreConfig_Write(config);
return _Py_INIT_OK();
}
-/* Parse the command line arguments */
static _PyInitError
-pymain_parse_cmdline_impl(_PyCoreConfig *config, _PyCmdline *cmdline,
- int *need_usage)
+pymain_init_python_main(PyInterpreterState *interp)
{
_PyInitError err;
- _PyOS_ResetGetOpt();
- do {
- int longindex = -1;
- int c = _PyOS_GetOpt(cmdline->args->argc, cmdline->argv, PROGRAM_OPTS,
- longoptions, &longindex);
- if (c == EOF) {
- break;
- }
-
- if (c == 'c') {
- /* -c is the last option; following arguments
- that look like options are left for the
- command to interpret. */
- size_t len = wcslen(_PyOS_optarg) + 1 + 1;
- wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len);
- if (command == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
- memcpy(command, _PyOS_optarg, (len - 2) * sizeof(wchar_t));
- command[len - 2] = '\n';
- command[len - 1] = 0;
- config->run_command = command;
- break;
- }
-
- if (c == 'm') {
- /* -m is the last option; following arguments
- that look like options are left for the
- module to interpret. */
- config->run_module = _PyMem_RawWcsdup(_PyOS_optarg);
- if (config->run_module == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
- break;
- }
-
- switch (c) {
- case 0:
- // Handle long option.
- assert(longindex == 0); // Only one long option now.
- if (!wcscmp(_PyOS_optarg, L"always")) {
- config->_check_hash_pycs_mode = "always";
- } else if (!wcscmp(_PyOS_optarg, L"never")) {
- config->_check_hash_pycs_mode = "never";
- } else if (!wcscmp(_PyOS_optarg, L"default")) {
- config->_check_hash_pycs_mode = "default";
- } else {
- fprintf(stderr, "--check-hash-based-pycs must be one of "
- "'default', 'always', or 'never'\n");
- *need_usage = 1;
- return _Py_INIT_OK();
- }
- break;
-
- case 'b':
- config->bytes_warning++;
- break;
-
- case 'd':
- config->parser_debug++;
- break;
-
- case 'i':
- config->inspect++;
- config->interactive++;
- break;
-
- case 'I':
- config->isolated++;
- break;
-
- /* case 'J': reserved for Jython */
-
- case 'O':
- config->optimization_level++;
- break;
-
- case 'B':
- config->write_bytecode = 0;
- break;
-
- case 's':
- config->user_site_directory = 0;
- break;
-
- case 'S':
- config->site_import = 0;
- break;
-
- case 'E':
- config->use_environment = 0;
- break;
-
- case 't':
- /* ignored for backwards compatibility */
- break;
-
- case 'u':
- config->buffered_stdio = 0;
- break;
-
- case 'v':
- config->verbose++;
- break;
-
- case 'x':
- config->skip_source_first_line = 1;
- break;
-
- case 'h':
- case '?':
- cmdline->print_help++;
- break;
-
- case 'V':
- cmdline->print_version++;
- break;
-
- case 'W':
- err = _Py_wstrlist_append(&cmdline->nwarnoption,
- &cmdline->warnoptions,
- _PyOS_optarg);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
- break;
-
- case 'X':
- err = _Py_wstrlist_append(&config->nxoption,
- &config->xoptions,
- _PyOS_optarg);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
- break;
-
- case 'q':
- config->quiet++;
- break;
-
- case 'R':
- config->use_hash_seed = 0;
- break;
-
- /* This space reserved for other options */
- default:
- /* unknown argument: parsing failed */
- *need_usage = 1;
- return _Py_INIT_OK();
- }
- } while (1);
-
- if (config->run_command == NULL && config->run_module == NULL
- && _PyOS_optind < cmdline->args->argc
- && wcscmp(cmdline->argv[_PyOS_optind], L"-") != 0)
- {
- config->run_filename = _PyMem_RawWcsdup(cmdline->argv[_PyOS_optind]);
- if (config->run_filename == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
- }
-
- if (config->run_command != NULL || config->run_module != NULL) {
- /* Backup _PyOS_optind */
- _PyOS_optind--;
- }
-
- /* -c and -m options are exclusive */
- assert(!(config->run_command != NULL && config->run_module != NULL));
-
- return _Py_INIT_OK();
-}
-
-
-static int
-add_xoption(PyObject *opts, const wchar_t *s)
-{
- PyObject *name, *value;
-
- const wchar_t *name_end = wcschr(s, L'=');
- if (!name_end) {
- name = PyUnicode_FromWideChar(s, -1);
- value = Py_True;
- Py_INCREF(value);
- }
- else {
- name = PyUnicode_FromWideChar(s, name_end - s);
- value = PyUnicode_FromWideChar(name_end + 1, -1);
- }
- if (name == NULL || value == NULL) {
- goto error;
- }
- if (PyDict_SetItem(opts, name, value) < 0) {
- goto error;
- }
- Py_DECREF(name);
- Py_DECREF(value);
- return 0;
-
-error:
- Py_XDECREF(name);
- Py_XDECREF(value);
- return -1;
-}
-
-
-static PyObject*
-config_create_xoptions_dict(const _PyCoreConfig *config)
-{
- int nxoption = config->nxoption;
- wchar_t **xoptions = config->xoptions;
- PyObject *dict = PyDict_New();
- if (dict == NULL) {
- return NULL;
- }
-
- for (int i=0; i < nxoption; i++) {
- wchar_t *option = xoptions[i];
- if (add_xoption(dict, option) < 0) {
- Py_DECREF(dict);
- return NULL;
- }
+ _PyMainInterpreterConfig main_config = _PyMainInterpreterConfig_INIT;
+ err = _PyMainInterpreterConfig_Read(&main_config, &interp->core_config);
+ if (!_Py_INIT_FAILED(err)) {
+ err = _Py_InitializeMainInterpreter(interp, &main_config);
}
+ _PyMainInterpreterConfig_Clear(&main_config);
- return dict;
-}
-
-
-static _PyInitError
-config_add_warnings_optlist(_PyCoreConfig *config, int len, wchar_t **options)
-{
- for (int i = 0; i < len; i++) {
- _PyInitError err = _Py_wstrlist_append(&config->nwarnoption,
- &config->warnoptions,
- options[i]);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
+ if (_Py_INIT_FAILED(err)) {
+ return err;
}
return _Py_INIT_OK();
}
static _PyInitError
-config_init_warnoptions(_PyCoreConfig *config, _PyCmdline *cmdline)
+pymain_init(const _PyArgv *args, PyInterpreterState **interp_p)
{
_PyInitError err;
- assert(config->nwarnoption == 0);
-
- /* The priority order for warnings configuration is (highest precedence
- * first):
- *
- * - the BytesWarning filter, if needed ('-b', '-bb')
- * - any '-W' command line options; then
- * - the 'PYTHONWARNINGS' environment variable; then
- * - the dev mode filter ('-X dev', 'PYTHONDEVMODE'); then
- * - any implicit filters added by _warnings.c/warnings.py
- *
- * All settings except the last are passed to the warnings module via
- * the `sys.warnoptions` list. Since the warnings module works on the basis
- * of "the most recently added filter will be checked first", we add
- * the lowest precedence entries first so that later entries override them.
+ err = _PyRuntime_Initialize();
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
+ /* 754 requires that FP exceptions run in "no stop" mode by default,
+ * and until C vendors implement C99's ways to control FP exceptions,
+ * Python requires non-stop mode. Alas, some platforms enable FP
+ * exceptions by default. Here we disable them.
*/
+#ifdef __FreeBSD__
+ fedisableexcept(FE_OVERFLOW);
+#endif
- if (config->dev_mode) {
- err = _Py_wstrlist_append(&config->nwarnoption,
- &config->warnoptions,
- L"default");
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
- }
+ _PyCoreConfig local_config = _PyCoreConfig_INIT;
+ _PyCoreConfig *config = &local_config;
- err = config_add_warnings_optlist(config,
- cmdline->nenv_warnoption,
- cmdline->env_warnoptions);
+ err = config_read_write(config, args);
if (_Py_INIT_FAILED(err)) {
- return err;
+ goto done;
}
- err = config_add_warnings_optlist(config,
- cmdline->nwarnoption,
- cmdline->warnoptions);
+ PyInterpreterState *interp;
+ err = _Py_InitializeCore(&interp, config);
if (_Py_INIT_FAILED(err)) {
- return err;
+ goto done;
}
+ *interp_p = interp;
- /* If the bytes_warning_flag isn't set, bytesobject.c and bytearrayobject.c
- * don't even try to emit a warning, so we skip setting the filter in that
- * case.
- */
- if (config->bytes_warning) {
- wchar_t *filter;
- if (config->bytes_warning> 1) {
- filter = L"error::BytesWarning";
- }
- else {
- filter = L"default::BytesWarning";
- }
- err = _Py_wstrlist_append(&config->nwarnoption,
- &config->warnoptions,
- filter);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
+ err = pymain_init_python_main(interp);
+ if (_Py_INIT_FAILED(err)) {
+ goto done;
}
- return _Py_INIT_OK();
-}
-
-/* Get warning options from PYTHONWARNINGS environment variable. */
-static _PyInitError
-cmdline_init_env_warnoptions(const _PyCoreConfig *config, _PyCmdline *cmdline)
-{
- wchar_t *env;
- int res = _PyCoreConfig_GetEnvDup(config, &env,
- L"PYTHONWARNINGS", "PYTHONWARNINGS");
- if (res < 0) {
- return DECODE_LOCALE_ERR("PYTHONWARNINGS", res);
- }
+ err = _Py_INIT_OK();
- if (env == NULL) {
- return _Py_INIT_OK();
- }
+done:
+ config_clear(config);
+ return err;
+}
- wchar_t *warning, *context = NULL;
- for (warning = WCSTOK(env, L",", &context);
- warning != NULL;
- warning = WCSTOK(NULL, L",", &context))
- {
- _PyInitError err = _Py_wstrlist_append(&cmdline->nenv_warnoption,
- &cmdline->env_warnoptions,
- warning);
- if (_Py_INIT_FAILED(err)) {
- PyMem_RawFree(env);
- return err;
- }
- }
- PyMem_RawFree(env);
- return _Py_INIT_OK();
-}
+/* --- pymain_run_python() ---------------------------------------- */
+/* Non-zero if filename, command (-c) or module (-m) is set
+ on the command line */
+#define RUN_CODE(config) \
+ (config->run_command != NULL || config->run_filename != NULL \
+ || config->run_module != NULL)
/* Return non-zero is stdin is a TTY or if -i command line option is used */
static int
@@ -877,128 +403,84 @@ stdin_is_interactive(const _PyCoreConfig *config)
}
-static void
-pymain_init_stdio(_PyCoreConfig *config)
+static PyObject *
+pymain_get_importer(const wchar_t *filename)
{
-#if defined(MS_WINDOWS) || defined(__CYGWIN__)
- /* don't translate newlines (\r\n <=> \n) */
- _setmode(fileno(stdin), O_BINARY);
- _setmode(fileno(stdout), O_BINARY);
- _setmode(fileno(stderr), O_BINARY);
-#endif
+ PyObject *sys_path0 = NULL, *importer;
- if (!config->buffered_stdio) {
-#ifdef HAVE_SETVBUF
- setvbuf(stdin, (char *)NULL, _IONBF, BUFSIZ);
- setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
- setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
-#else /* !HAVE_SETVBUF */
- setbuf(stdin, (char *)NULL);
- setbuf(stdout, (char *)NULL);
- setbuf(stderr, (char *)NULL);
-#endif /* !HAVE_SETVBUF */
- }
- else if (config->interactive) {
-#ifdef MS_WINDOWS
- /* Doesn't have to have line-buffered -- use unbuffered */
- /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */
- setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
-#else /* !MS_WINDOWS */
-#ifdef HAVE_SETVBUF
- setvbuf(stdin, (char *)NULL, _IOLBF, BUFSIZ);
- setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
-#endif /* HAVE_SETVBUF */
-#endif /* !MS_WINDOWS */
- /* Leave stderr alone - it should be unbuffered anyway. */
+ sys_path0 = PyUnicode_FromWideChar(filename, wcslen(filename));
+ if (sys_path0 == NULL) {
+ goto error;
}
-}
-
-static void
-pymain_header(const _PyCoreConfig *config)
-{
- if (config->quiet) {
- return;
+ importer = PyImport_GetImporter(sys_path0);
+ if (importer == NULL) {
+ goto error;
}
- if (!config->verbose && (RUN_CODE(config) || !stdin_is_interactive(config))) {
- return;
+ if (importer == Py_None) {
+ Py_DECREF(sys_path0);
+ Py_DECREF(importer);
+ return NULL;
}
- fprintf(stderr, "Python %s on %s\n", Py_GetVersion(), Py_GetPlatform());
- if (config->site_import) {
- fprintf(stderr, "%s\n", COPYRIGHT);
- }
+ Py_DECREF(importer);
+ return sys_path0;
+
+error:
+ Py_XDECREF(sys_path0);
+ PySys_WriteStderr("Failed checking if argv[0] is an import path entry\n");
+ PyErr_Print();
+ return NULL;
}
-static _PyInitError
-pymain_init_core_argv(_PyCoreConfig *config, _PyCmdline *cmdline)
+static int
+pymain_sys_path_add_path0(PyInterpreterState *interp, PyObject *path0)
{
- /* Copy argv to be able to modify it (to force -c/-m) */
- int argc = cmdline->args->argc - _PyOS_optind;
- wchar_t **argv;
-
- if (argc <= 0 || cmdline->argv == NULL) {
- /* Ensure at least one (empty) argument is seen */
- static wchar_t *empty_argv[1] = {L""};
- argc = 1;
- argv = _Py_wstrlist_copy(1, empty_argv);
+ _Py_IDENTIFIER(path);
+ PyObject *sys_path;
+ PyObject *sysdict = interp->sysdict;
+ if (sysdict != NULL) {
+ sys_path = _PyDict_GetItemIdWithError(sysdict, &PyId_path);
+ if (sys_path == NULL && PyErr_Occurred()) {
+ goto error;
+ }
}
else {
- argv = _Py_wstrlist_copy(argc, &cmdline->argv[_PyOS_optind]);
- }
-
- if (argv == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
-
- wchar_t *arg0 = NULL;
- if (config->run_command != NULL) {
- /* Force sys.argv[0] = '-c' */
- arg0 = L"-c";
+ sys_path = NULL;
}
- else if (config->run_module != NULL) {
- /* Force sys.argv[0] = '-m'*/
- arg0 = L"-m";
+ if (sys_path == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path");
+ goto error;
}
- if (arg0 != NULL) {
- arg0 = _PyMem_RawWcsdup(arg0);
- if (arg0 == NULL) {
- _Py_wstrlist_clear(argc, argv);
- return _Py_INIT_NO_MEMORY();
- }
- assert(argc >= 1);
- PyMem_RawFree(argv[0]);
- argv[0] = arg0;
+ if (PyList_Insert(sys_path, 0, path0)) {
+ goto error;
}
+ return 0;
- config->argc = argc;
- config->argv = argv;
- return _Py_INIT_OK();
+error:
+ PyErr_Print();
+ return -1;
}
-PyObject*
-_Py_wstrlist_as_pylist(int len, wchar_t **list)
+static void
+pymain_header(const _PyCoreConfig *config)
{
- assert(list != NULL || len < 1);
+ if (config->quiet) {
+ return;
+ }
- PyObject *pylist = PyList_New(len);
- if (pylist == NULL) {
- return NULL;
+ if (!config->verbose && (RUN_CODE(config) || !stdin_is_interactive(config))) {
+ return;
}
- for (int i = 0; i < len; i++) {
- PyObject *v = PyUnicode_FromWideChar(list[i], -1);
- if (v == NULL) {
- Py_DECREF(pylist);
- return NULL;
- }
- PyList_SET_ITEM(pylist, i, v);
+ fprintf(stderr, "Python %s on %s\n", Py_GetVersion(), Py_GetPlatform());
+ if (config->site_import) {
+ fprintf(stderr, "%s\n", COPYRIGHT);
}
- return pylist;
}
@@ -1025,29 +507,82 @@ pymain_import_readline(const _PyCoreConfig *config)
}
-static void
-pymain_run_startup(_PyCoreConfig *config, PyCompilerFlags *cf)
+static int
+pymain_run_command(wchar_t *command, PyCompilerFlags *cf)
{
- const char *startup = _PyCoreConfig_GetEnv(config, "PYTHONSTARTUP");
- if (startup == NULL) {
- return;
+ PyObject *unicode, *bytes;
+ int ret;
+
+ unicode = PyUnicode_FromWideChar(command, -1);
+ if (unicode == NULL) {
+ goto error;
}
- FILE *fp = _Py_fopen(startup, "r");
- if (fp == NULL) {
- int save_errno = errno;
- PySys_WriteStderr("Could not open PYTHONSTARTUP\n");
- errno = save_errno;
+ bytes = PyUnicode_AsUTF8String(unicode);
+ Py_DECREF(unicode);
+ if (bytes == NULL) {
+ goto error;
+ }
- PyErr_SetFromErrnoWithFilename(PyExc_OSError,
- startup);
+ ret = PyRun_SimpleStringFlags(PyBytes_AsString(bytes), cf);
+ Py_DECREF(bytes);
+ return (ret != 0);
+
+error:
+ PySys_WriteStderr("Unable to decode the command from the command line:\n");
+ PyErr_Print();
+ return 1;
+}
+
+
+static int
+pymain_run_module(const wchar_t *modname, int set_argv0)
+{
+ PyObject *module, *runpy, *runmodule, *runargs, *result;
+ runpy = PyImport_ImportModule("runpy");
+ if (runpy == NULL) {
+ fprintf(stderr, "Could not import runpy module\n");
PyErr_Print();
- return;
+ return -1;
}
-
- (void) PyRun_SimpleFileExFlags(fp, startup, 0, cf);
- PyErr_Clear();
- fclose(fp);
+ runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main");
+ if (runmodule == NULL) {
+ fprintf(stderr, "Could not access runpy._run_module_as_main\n");
+ PyErr_Print();
+ Py_DECREF(runpy);
+ return -1;
+ }
+ module = PyUnicode_FromWideChar(modname, wcslen(modname));
+ if (module == NULL) {
+ fprintf(stderr, "Could not convert module name to unicode\n");
+ PyErr_Print();
+ Py_DECREF(runpy);
+ Py_DECREF(runmodule);
+ return -1;
+ }
+ runargs = Py_BuildValue("(Oi)", module, set_argv0);
+ if (runargs == NULL) {
+ fprintf(stderr,
+ "Could not create arguments for runpy._run_module_as_main\n");
+ PyErr_Print();
+ Py_DECREF(runpy);
+ Py_DECREF(runmodule);
+ Py_DECREF(module);
+ return -1;
+ }
+ result = PyObject_Call(runmodule, runargs, NULL);
+ if (result == NULL) {
+ PyErr_Print();
+ }
+ Py_DECREF(runpy);
+ Py_DECREF(runmodule);
+ Py_DECREF(module);
+ Py_DECREF(runargs);
+ if (result == NULL) {
+ return -1;
+ }
+ Py_DECREF(result);
+ return 0;
}
@@ -1121,6 +656,63 @@ pymain_run_file(_PyCoreConfig *config, PyCompilerFlags *cf)
}
+static void
+pymain_run_startup(_PyCoreConfig *config, PyCompilerFlags *cf)
+{
+ const char *startup = _PyCoreConfig_GetEnv(config, "PYTHONSTARTUP");
+ if (startup == NULL) {
+ return;
+ }
+
+ FILE *fp = _Py_fopen(startup, "r");
+ if (fp == NULL) {
+ int save_errno = errno;
+ PySys_WriteStderr("Could not open PYTHONSTARTUP\n");
+ errno = save_errno;
+
+ PyErr_SetFromErrnoWithFilename(PyExc_OSError,
+ startup);
+ PyErr_Print();
+ return;
+ }
+
+ (void) PyRun_SimpleFileExFlags(fp, startup, 0, cf);
+ PyErr_Clear();
+ fclose(fp);
+}
+
+
+static void
+pymain_run_interactive_hook(void)
+{
+ PyObject *sys, *hook, *result;
+ sys = PyImport_ImportModule("sys");
+ if (sys == NULL) {
+ goto error;
+ }
+
+ hook = PyObject_GetAttrString(sys, "__interactivehook__");
+ Py_DECREF(sys);
+ if (hook == NULL) {
+ PyErr_Clear();
+ return;
+ }
+
+ result = _PyObject_CallNoArg(hook);
+ Py_DECREF(hook);
+ if (result == NULL) {
+ goto error;
+ }
+ Py_DECREF(result);
+
+ return;
+
+error:
+ PySys_WriteStderr("Failed calling sys.__interactivehook__\n");
+ PyErr_Print();
+}
+
+
static int
pymain_run_stdin(_PyCoreConfig *config, PyCompilerFlags *cf)
{
@@ -1165,392 +757,6 @@ pymain_repl(_PyCoreConfig *config, PyCompilerFlags *cf, int *exitcode)
}
-/* Parse the command line.
- Handle --version and --help options directly. */
-static _PyInitError
-pymain_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline)
-{
- int need_usage = 0;
- _PyInitError err;
- err = pymain_parse_cmdline_impl(config, cmdline, &need_usage);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
-
- if (need_usage) {
- pymain_usage(1, config->program);
- return _Py_INIT_EXIT(2);
- }
- return _Py_INIT_OK();
-}
-
-
-/* Parse command line options and environment variables.
- This code must not use Python runtime apart PyMem_Raw memory allocator. */
-static _PyInitError
-pymain_read_conf_impl(_PyCoreConfig *config, _PyCmdline *cmdline)
-{
- _PyInitError err;
-
- err = pymain_parse_cmdline(config, cmdline);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
-
- err = pymain_init_core_argv(config, cmdline);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
-
- err = _PyCoreConfig_Read(config);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
-
- if (config->use_environment) {
- err = cmdline_init_env_warnoptions(config, cmdline);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
- }
-
- err = config_init_warnoptions(config, cmdline);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
- return _Py_INIT_OK();
-}
-
-
-/* Read the configuration and initialize the LC_CTYPE locale:
- enable UTF-8 mode (PEP 540) and/or coerce the C locale (PEP 538). */
-static _PyInitError
-pymain_read_conf(_PyCoreConfig *config, _PyCmdline *cmdline)
-{
- _PyInitError err;
- int init_utf8_mode = Py_UTF8Mode;
-#ifdef MS_WINDOWS
- int init_legacy_encoding = Py_LegacyWindowsFSEncodingFlag;
-#endif
- _PyCoreConfig save_config = _PyCoreConfig_INIT;
- int locale_coerced = 0;
- int loops = 0;
-
- if (_PyCoreConfig_Copy(&save_config, config) < 0) {
- err = _Py_INIT_NO_MEMORY();
- goto done;
- }
-
- /* Set LC_CTYPE to the user preferred locale */
- _Py_SetLocaleFromEnv(LC_CTYPE);
-
- while (1) {
- int utf8_mode = config->utf8_mode;
- int encoding_changed = 0;
-
- /* Watchdog to prevent an infinite loop */
- loops++;
- if (loops == 3) {
- err = _Py_INIT_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
-
- err = pymain_init_cmdline_argv(config, cmdline);
- if (_Py_INIT_FAILED(err)) {
- goto done;
- }
-
- err = pymain_read_conf_impl(config, cmdline);
- if (_Py_INIT_FAILED(err)) {
- 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.
- */
- if (config->coerce_c_locale && !locale_coerced) {
- locale_coerced = 1;
- _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
- 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;
- if (_PyCoreConfig_Copy(config, &save_config) < 0) {
- err = _Py_INIT_NO_MEMORY();
- goto done;
- }
- pymain_clear_cmdline(cmdline);
- const _PyArgv *args = cmdline->args;
- memset(cmdline, 0, sizeof(*cmdline));
- cmdline->args = args;
- 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 */
- }
- err = _Py_INIT_OK();
-
-done:
- _PyCoreConfig_Clear(&save_config);
- Py_UTF8Mode = init_utf8_mode ;
-#ifdef MS_WINDOWS
- Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;
-#endif
- return err;
-}
-
-
-void
-_PyMainInterpreterConfig_Clear(_PyMainInterpreterConfig *config)
-{
- Py_CLEAR(config->argv);
- Py_CLEAR(config->executable);
- Py_CLEAR(config->prefix);
- Py_CLEAR(config->base_prefix);
- Py_CLEAR(config->exec_prefix);
- Py_CLEAR(config->base_exec_prefix);
- Py_CLEAR(config->warnoptions);
- Py_CLEAR(config->xoptions);
- Py_CLEAR(config->module_search_path);
- Py_CLEAR(config->pycache_prefix);
-}
-
-
-static PyObject*
-config_copy_attr(PyObject *obj)
-{
- if (PyUnicode_Check(obj)) {
- Py_INCREF(obj);
- return obj;
- }
- else if (PyList_Check(obj)) {
- return PyList_GetSlice(obj, 0, Py_SIZE(obj));
- }
- else if (PyDict_Check(obj)) {
- /* The dict type is used for xoptions. Make the assumption that keys
- and values are immutables */
- return PyDict_Copy(obj);
- }
- else {
- PyErr_Format(PyExc_TypeError,
- "cannot copy config attribute of type %.200s",
- Py_TYPE(obj)->tp_name);
- return NULL;
- }
-}
-
-
-int
-_PyMainInterpreterConfig_Copy(_PyMainInterpreterConfig *config,
- const _PyMainInterpreterConfig *config2)
-{
- _PyMainInterpreterConfig_Clear(config);
-
-#define COPY_ATTR(ATTR) config->ATTR = config2->ATTR
-#define COPY_OBJ_ATTR(ATTR) \
- do { \
- if (config2->ATTR != NULL) { \
- config->ATTR = config_copy_attr(config2->ATTR); \
- if (config->ATTR == NULL) { \
- return -1; \
- } \
- } \
- } while (0)
-
- COPY_ATTR(install_signal_handlers);
- COPY_OBJ_ATTR(argv);
- COPY_OBJ_ATTR(executable);
- COPY_OBJ_ATTR(prefix);
- COPY_OBJ_ATTR(base_prefix);
- COPY_OBJ_ATTR(exec_prefix);
- COPY_OBJ_ATTR(base_exec_prefix);
- COPY_OBJ_ATTR(warnoptions);
- COPY_OBJ_ATTR(xoptions);
- COPY_OBJ_ATTR(module_search_path);
- COPY_OBJ_ATTR(pycache_prefix);
-#undef COPY_ATTR
-#undef COPY_OBJ_ATTR
- return 0;
-}
-
-
-PyObject*
-_PyMainInterpreterConfig_AsDict(const _PyMainInterpreterConfig *config)
-{
- PyObject *dict, *obj;
- int res;
-
- dict = PyDict_New();
- if (dict == NULL) {
- return NULL;
- }
-
-#define SET_ITEM_INT(ATTR) \
- do { \
- obj = PyLong_FromLong(config->ATTR); \
- if (obj == NULL) { \
- goto fail; \
- } \
- res = PyDict_SetItemString(dict, #ATTR, obj); \
- Py_DECREF(obj); \
- if (res < 0) { \
- goto fail; \
- } \
- } while (0)
-
-#define SET_ITEM_OBJ(ATTR) \
- do { \
- obj = config->ATTR; \
- if (obj == NULL) { \
- obj = Py_None; \
- } \
- res = PyDict_SetItemString(dict, #ATTR, obj); \
- if (res < 0) { \
- goto fail; \
- } \
- } while (0)
-
- SET_ITEM_INT(install_signal_handlers);
- SET_ITEM_OBJ(argv);
- SET_ITEM_OBJ(executable);
- SET_ITEM_OBJ(prefix);
- SET_ITEM_OBJ(base_prefix);
- SET_ITEM_OBJ(exec_prefix);
- SET_ITEM_OBJ(base_exec_prefix);
- SET_ITEM_OBJ(warnoptions);
- SET_ITEM_OBJ(xoptions);
- SET_ITEM_OBJ(module_search_path);
- SET_ITEM_OBJ(pycache_prefix);
-
- return dict;
-
-fail:
- Py_DECREF(dict);
- return NULL;
-
-#undef SET_ITEM_OBJ
-}
-
-
-_PyInitError
-_PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config,
- const _PyCoreConfig *config)
-{
- if (main_config->install_signal_handlers < 0) {
- main_config->install_signal_handlers = config->install_signal_handlers;
- }
-
- if (main_config->xoptions == NULL) {
- main_config->xoptions = config_create_xoptions_dict(config);
- if (main_config->xoptions == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
- }
-
-#define COPY_WSTR(ATTR) \
- do { \
- if (main_config->ATTR == NULL && config->ATTR != NULL) { \
- main_config->ATTR = PyUnicode_FromWideChar(config->ATTR, -1); \
- if (main_config->ATTR == NULL) { \
- return _Py_INIT_NO_MEMORY(); \
- } \
- } \
- } while (0)
-#define COPY_WSTRLIST(ATTR, LEN, LIST) \
- do { \
- if (ATTR == NULL) { \
- ATTR = _Py_wstrlist_as_pylist(LEN, LIST); \
- if (ATTR == NULL) { \
- return _Py_INIT_NO_MEMORY(); \
- } \
- } \
- } while (0)
-
- COPY_WSTRLIST(main_config->warnoptions,
- config->nwarnoption, config->warnoptions);
- if (config->argc >= 0) {
- COPY_WSTRLIST(main_config->argv,
- config->argc, config->argv);
- }
-
- if (config->_install_importlib) {
- COPY_WSTR(executable);
- COPY_WSTR(prefix);
- COPY_WSTR(base_prefix);
- COPY_WSTR(exec_prefix);
- COPY_WSTR(base_exec_prefix);
-
- COPY_WSTRLIST(main_config->module_search_path,
- config->nmodule_search_path, config->module_search_paths);
-
- if (config->pycache_prefix != NULL) {
- COPY_WSTR(pycache_prefix);
- } else {
- main_config->pycache_prefix = NULL;
- }
-
- }
-
- return _Py_INIT_OK();
-#undef COPY_WSTR
-#undef COPY_WSTRLIST
-}
-
-
-static _PyInitError
-pymain_init_python_main(PyInterpreterState *interp)
-{
- _PyInitError err;
-
- _PyMainInterpreterConfig main_config = _PyMainInterpreterConfig_INIT;
- err = _PyMainInterpreterConfig_Read(&main_config, &interp->core_config);
- if (!_Py_INIT_FAILED(err)) {
- err = _Py_InitializeMainInterpreter(interp, &main_config);
- }
- _PyMainInterpreterConfig_Clear(&main_config);
-
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
- return _Py_INIT_OK();
-}
-
-
static _PyInitError
pymain_run_python(PyInterpreterState *interp, int *exitcode)
{
@@ -1620,129 +826,58 @@ done:
}
-static _PyInitError
-pymain_cmdline_impl(_PyCoreConfig *config, _PyCmdline *cmdline)
-{
- _PyInitError err;
-
- err = _PyRuntime_Initialize();
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
-
- err = pymain_read_conf(config, cmdline);
- if (_Py_INIT_FAILED(err)) {
- return err;
- }
-
- if (cmdline->print_help) {
- pymain_usage(0, config->program);
- return _Py_INIT_EXIT(0);
- }
-
- if (cmdline->print_version) {
- printf("Python %s\n",
- (cmdline->print_version >= 2) ? Py_GetVersion() : PY_VERSION);
- return _Py_INIT_EXIT(0);
- }
-
- /* For Py_GetArgcArgv(). Cleared by pymain_free(). */
- orig_argv = _Py_wstrlist_copy(cmdline->args->argc, cmdline->argv);
- if (orig_argv == NULL) {
- return _Py_INIT_NO_MEMORY();
- }
- orig_argc = cmdline->args->argc;
- return _Py_INIT_OK();
-}
-
-
-/* Read the configuration into _PyCoreConfig and _PyMain, initialize the
- LC_CTYPE locale and Py_DecodeLocale().
+/* --- pymain_main() ---------------------------------------------- */
- Configuration:
-
- * Command line arguments
- * Environment variables
- * Py_xxx global configuration variables
-
- _PyCmdline is a temporary structure used to prioritize these
- variables. */
-static _PyInitError
-pymain_cmdline(_PyArgv *args, _PyCoreConfig *config)
+static void
+pymain_free(void)
{
- /* Force default allocator, since pymain_free() and pymain_clear_config()
- must use the same allocator than this function. */
- PyMemAllocatorEx old_alloc;
- _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
-#ifdef Py_DEBUG
- PyMemAllocatorEx default_alloc;
- PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &default_alloc);
-#endif
-
- _PyCmdline cmdline;
- memset(&cmdline, 0, sizeof(cmdline));
- cmdline.args = args;
-
- _PyInitError err = pymain_cmdline_impl(config, &cmdline);
-
- pymain_clear_cmdline(&cmdline);
+ _PyImport_Fini2();
-#ifdef Py_DEBUG
- /* Make sure that PYMEM_DOMAIN_RAW has not been modified */
- PyMemAllocatorEx cur_alloc;
- PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &cur_alloc);
- assert(memcmp(&cur_alloc, &default_alloc, sizeof(cur_alloc)) == 0);
-#endif
- PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
- return err;
+ /* Free global variables which cannot be freed in Py_Finalize():
+ configuration options set before Py_Initialize() which should
+ remain valid after Py_Finalize(), since
+ Py_Initialize()-Py_Finalize() can be called multiple times. */
+ _PyPathConfig_ClearGlobal();
+ _Py_ClearStandardStreamEncoding();
+ _Py_ClearArgcArgv();
+#ifdef __INSURE__
+ /* Insure++ is a memory analysis tool that aids in discovering
+ * memory leaks and other memory problems. On Python exit, the
+ * interned string dictionaries are flagged as being in use at exit
+ * (which it is). Under normal circumstances, this is fine because
+ * the memory will be automatically reclaimed by the system. Under
+ * memory debugging, it's a huge source of useless noise, so we
+ * trade off slower shutdown for less distraction in the memory
+ * reports. -baw
+ */
+ _Py_ReleaseInternedUnicodeStrings();
+#endif /* __INSURE__ */
}
-static _PyInitError
-pymain_init(_PyArgv *args, PyInterpreterState **interp_p)
+static int
+exit_sigint(void)
{
- _PyInitError err;
-
- /* 754 requires that FP exceptions run in "no stop" mode by default,
- * and until C vendors implement C99's ways to control FP exceptions,
- * Python requires non-stop mode. Alas, some platforms enable FP
- * exceptions by default. Here we disable them.
- */
-#ifdef __FreeBSD__
- fedisableexcept(FE_OVERFLOW);
-#endif
-
- _PyCoreConfig local_config = _PyCoreConfig_INIT;
- _PyCoreConfig *config = &local_config;
-
- _PyCoreConfig_GetGlobalConfig(config);
-
- err = pymain_cmdline(args, config);
- if (_Py_INIT_FAILED(err)) {
- goto done;
- }
-
- _PyCoreConfig_SetGlobalConfig(config);
-
- pymain_init_stdio(config);
-
- PyInterpreterState *interp;
- err = _Py_InitializeCore(&interp, config);
- if (_Py_INIT_FAILED(err)) {
- goto done;
- }
- *interp_p = interp;
-
- err = pymain_init_python_main(interp);
- if (_Py_INIT_FAILED(err)) {
- goto done;
+ /* bpo-1054041: We need to exit via the
+ * SIG_DFL handler for SIGINT if KeyboardInterrupt went unhandled.
+ * If we don't, a calling process such as a shell may not know
+ * about the user's ^C. https://www.cons.org/cracauer/sigint.html */
+#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
+ if (PyOS_setsig(SIGINT, SIG_DFL) == SIG_ERR) {
+ perror("signal"); /* Impossible in normal environments. */
+ } else {
+ kill(getpid(), SIGINT);
}
-
- err = _Py_INIT_OK();
-
-done:
- pymain_clear_config(config);
- return err;
+ /* If setting SIG_DFL failed, or kill failed to terminate us,
+ * there isn't much else we can do aside from an error code. */
+#endif /* HAVE_GETPID && !MS_WINDOWS */
+#ifdef MS_WINDOWS
+ /* cmd.exe detects this, prints ^C, and offers to terminate. */
+ /* https://msdn.microsoft.com/en-us/library/cc704588.aspx */
+ return STATUS_CONTROL_C_EXIT;
+#else
+ return SIGINT + 128;
+#endif /* !MS_WINDOWS */
}
@@ -1772,26 +907,7 @@ pymain_main(_PyArgv *args)
pymain_free();
if (_Py_UnhandledKeyboardInterrupt) {
- /* https://bugs.python.org/issue1054041 - We need to exit via the
- * SIG_DFL handler for SIGINT if KeyboardInterrupt went unhandled.
- * If we don't, a calling process such as a shell may not know
- * about the user's ^C. https://www.cons.org/cracauer/sigint.html */
-#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
- if (PyOS_setsig(SIGINT, SIG_DFL) == SIG_ERR) {
- perror("signal"); /* Impossible in normal environments. */
- } else {
- kill(getpid(), SIGINT);
- }
- /* If setting SIG_DFL failed, or kill failed to terminate us,
- * there isn't much else we can do aside from an error code. */
-#endif /* HAVE_GETPID && !MS_WINDOWS */
-#ifdef MS_WINDOWS
- /* cmd.exe detects this, prints ^C, and offers to terminate. */
- /* https://msdn.microsoft.com/en-us/library/cc704588.aspx */
- exitcode = STATUS_CONTROL_C_EXIT;
-#else
- exitcode = SIGINT + 128;
-#endif /* !MS_WINDOWS */
+ exitcode = exit_sigint();
}
return exitcode;
@@ -1821,21 +937,6 @@ _Py_UnixMain(int argc, char **argv)
return pymain_main(&args);
}
-
-/* this is gonna seem *real weird*, but if you put some other code between
- Py_Main() and Py_GetArgcArgv() you will need to adjust the test in the
- while statement in Misc/gdbinit:ppystack */
-
-/* Make the *original* argc/argv available to other modules.
- This is rare, but it is needed by the secureware extension. */
-
-void
-Py_GetArgcArgv(int *argc, wchar_t ***argv)
-{
- *argc = orig_argc;
- *argv = orig_argv;
-}
-
#ifdef __cplusplus
}
#endif
diff --git a/Python/coreconfig.c b/Python/coreconfig.c
index d9b3013..47dbe66 100644
--- a/Python/coreconfig.c
+++ b/Python/coreconfig.c
@@ -1,35 +1,116 @@
#include "Python.h"
+#include "osdefs.h" /* DELIM */
#include "pycore_coreconfig.h"
#include "pycore_fileutils.h"
+#include "pycore_getopt.h"
#include "pycore_pylifecycle.h"
#include "pycore_pymem.h"
#include "pycore_pathconfig.h"
-#include "pycore_pystate.h"
-#include <locale.h>
+#include <locale.h> /* setlocale() */
#ifdef HAVE_LANGINFO_H
-# include <langinfo.h>
+# include <langinfo.h> /* nl_langinfo(CODESET) */
#endif
-
-#include <locale.h> /* setlocale() */
-#ifdef HAVE_LANGINFO_H
-#include <langinfo.h> /* nl_langinfo(CODESET) */
+#if defined(MS_WINDOWS) || defined(__CYGWIN__)
+# include <windows.h> /* GetACP() */
+# ifdef HAVE_IO_H
+# include <io.h>
+# endif
+# ifdef HAVE_FCNTL_H
+# include <fcntl.h> /* O_BINARY */
+# endif
#endif
-#define DECODE_LOCALE_ERR(NAME, LEN) \
- (((LEN) == -2) \
- ? _Py_INIT_USER_ERR("cannot decode " NAME) \
- : _Py_INIT_NO_MEMORY())
+/* --- Command line options --------------------------------------- */
+
+#define PROGRAM_OPTS L"bBc:dEhiIJm:OqRsStuvVW:xX:?"
+
+static const _PyOS_LongOption longoptions[] = {
+ {L"check-hash-based-pycs", 1, 0},
+ {NULL, 0, 0},
+};
+
+/* Short usage message (with %s for argv0) */
+static const char usage_line[] =
+"usage: %ls [option] ... [-c cmd | -m mod | file | -] [arg] ...\n";
+
+/* Long usage message, split into parts < 512 bytes */
+static const char usage_1[] = "\
+Options and arguments (and corresponding environment variables):\n\
+-b : issue warnings about str(bytes_instance), str(bytearray_instance)\n\
+ and comparing bytes/bytearray with str. (-bb: issue errors)\n\
+-B : don't write .pyc files on import; also PYTHONDONTWRITEBYTECODE=x\n\
+-c cmd : program passed in as string (terminates option list)\n\
+-d : debug output from parser; also PYTHONDEBUG=x\n\
+-E : ignore PYTHON* environment variables (such as PYTHONPATH)\n\
+-h : print this help message and exit (also --help)\n\
+";
+static const char usage_2[] = "\
+-i : inspect interactively after running script; forces a prompt even\n\
+ if stdin does not appear to be a terminal; also PYTHONINSPECT=x\n\
+-I : isolate Python from the user's environment (implies -E and -s)\n\
+-m mod : run library module as a script (terminates option list)\n\
+-O : remove assert and __debug__-dependent statements; add .opt-1 before\n\
+ .pyc extension; also PYTHONOPTIMIZE=x\n\
+-OO : do -O changes and also discard docstrings; add .opt-2 before\n\
+ .pyc extension\n\
+-q : don't print version and copyright messages on interactive startup\n\
+-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\
+-S : don't imply 'import site' on initialization\n\
+";
+static const char usage_3[] = "\
+-u : force the stdout and stderr streams to be unbuffered;\n\
+ this option has no effect on stdin; also PYTHONUNBUFFERED=x\n\
+-v : verbose (trace import statements); also PYTHONVERBOSE=x\n\
+ can be supplied multiple times to increase verbosity\n\
+-V : print the Python version number and exit (also --version)\n\
+ when given twice, print more information about the build\n\
+-W arg : warning control; arg is action:message:category:module:lineno\n\
+ also PYTHONWARNINGS=arg\n\
+-x : skip first line of source, allowing use of non-Unix forms of #!cmd\n\
+-X opt : set implementation-specific option\n\
+--check-hash-based-pycs always|default|never:\n\
+ control how Python invalidates hash-based .pyc files\n\
+";
+static const char usage_4[] = "\
+file : program read from script file\n\
+- : program read from stdin (default; interactive mode if a tty)\n\
+arg ...: arguments passed to program in sys.argv[1:]\n\n\
+Other environment variables:\n\
+PYTHONSTARTUP: file executed on interactive startup (no default)\n\
+PYTHONPATH : '%lc'-separated list of directories prefixed to the\n\
+ default module search path. The result is sys.path.\n\
+";
+static const char usage_5[] =
+"PYTHONHOME : alternate <prefix> directory (or <prefix>%lc<exec_prefix>).\n"
+" The default module search path uses %s.\n"
+"PYTHONCASEOK : ignore case in 'import' statements (Windows).\n"
+"PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n"
+"PYTHONFAULTHANDLER: dump the Python traceback on fatal errors.\n";
+static const char usage_6[] =
+"PYTHONHASHSEED: if this variable is set to 'random', a random value is used\n"
+" to seed the hashes of str, bytes and datetime objects. It can also be\n"
+" set to an integer in the range [0,4294967295] to get hash values with a\n"
+" predictable seed.\n"
+"PYTHONMALLOC: set the Python memory allocators and/or install debug hooks\n"
+" on Python memory allocators. Use PYTHONMALLOC=debug to install debug\n"
+" hooks.\n"
+"PYTHONCOERCECLOCALE: if this variable is set to 0, it disables the locale\n"
+" coercion behavior. Use PYTHONCOERCECLOCALE=warn to request display of\n"
+" locale coercion and locale compatibility warnings on stderr.\n"
+"PYTHONBREAKPOINT: if this variable is set to 0, it disables the default\n"
+" debugger. It can be set to the callable of your debugger of choice.\n"
+"PYTHONDEVMODE: enable the development mode.\n"
+"PYTHONPYCACHEPREFIX: root directory for bytecode cache (pyc) files.\n";
+
+#if defined(MS_WINDOWS)
+# define PYTHONHOMEHELP "<prefix>\\python{major}{minor}"
+#else
+# define PYTHONHOMEHELP "<prefix>/lib/pythonX.X"
+#endif
-/* Global configuration variables */
-
-/* The filesystem encoding is chosen by config_init_fs_encoding(),
- see also initfsencoding(). */
-const char *Py_FileSystemDefaultEncoding = NULL;
-int Py_HasFileSystemDefaultEncoding = 0;
-const char *Py_FileSystemDefaultEncodeErrors = NULL;
-static int _Py_HasFileSystemDefaultEncodeErrors = 0;
+/* --- Global configuration variables ----------------------------- */
/* UTF-8 mode (PEP 540): if equals to 1, use the UTF-8 encoding, and change
stdin and stdout error handler to "surrogateescape". It is equal to
@@ -55,6 +136,13 @@ int Py_LegacyWindowsFSEncodingFlag = 0; /* Uses mbcs instead of utf-8 */
int Py_LegacyWindowsStdioFlag = 0; /* Uses FileIO instead of WindowsConsoleIO */
#endif
+/* The filesystem encoding is chosen by config_init_fs_encoding(),
+ see also initfsencoding(). */
+const char *Py_FileSystemDefaultEncoding = NULL;
+int Py_HasFileSystemDefaultEncoding = 0;
+const char *Py_FileSystemDefaultEncodeErrors = NULL;
+static int _Py_HasFileSystemDefaultEncodeErrors = 0;
+
PyObject *
_Py_GetGlobalVariablesAsDict(void)
@@ -128,6 +216,8 @@ fail:
}
+/* --- _Py_wstrlist ----------------------------------------------- */
+
void
_Py_wstrlist_clear(int len, wchar_t **list)
{
@@ -139,7 +229,7 @@ _Py_wstrlist_clear(int len, wchar_t **list)
wchar_t**
-_Py_wstrlist_copy(int len, wchar_t **list)
+_Py_wstrlist_copy(int len, wchar_t * const *list)
{
assert((len > 0 && list != NULL) || len == 0);
size_t size = len * sizeof(list[0]);
@@ -159,6 +249,53 @@ _Py_wstrlist_copy(int len, wchar_t **list)
}
+_PyInitError
+_Py_wstrlist_append(int *len, wchar_t ***list, const wchar_t *str)
+{
+ if (*len == INT_MAX) {
+ /* len+1 would overflow */
+ return _Py_INIT_NO_MEMORY();
+ }
+ wchar_t *str2 = _PyMem_RawWcsdup(str);
+ if (str2 == NULL) {
+ return _Py_INIT_NO_MEMORY();
+ }
+
+ size_t size = (*len + 1) * sizeof(list[0]);
+ wchar_t **list2 = (wchar_t **)PyMem_RawRealloc(*list, size);
+ if (list2 == NULL) {
+ PyMem_RawFree(str2);
+ return _Py_INIT_NO_MEMORY();
+ }
+ list2[*len] = str2;
+ *list = list2;
+ (*len)++;
+ return _Py_INIT_OK();
+}
+
+
+PyObject*
+_Py_wstrlist_as_pylist(int len, wchar_t **list)
+{
+ assert(list != NULL || len < 1);
+
+ PyObject *pylist = PyList_New(len);
+ if (pylist == NULL) {
+ return NULL;
+ }
+
+ for (int i = 0; i < len; i++) {
+ PyObject *v = PyUnicode_FromWideChar(list[i], -1);
+ if (v == NULL) {
+ Py_DECREF(pylist);
+ return NULL;
+ }
+ PyList_SET_ITEM(pylist, i, v);
+ }
+ return pylist;
+}
+
+
void
_Py_ClearFileSystemEncoding(void)
{
@@ -173,6 +310,8 @@ _Py_ClearFileSystemEncoding(void)
}
+/* --- File system encoding/errors -------------------------------- */
+
/* Set Py_FileSystemDefaultEncoding and Py_FileSystemDefaultEncodeErrors
global configuration variables. */
int
@@ -200,6 +339,8 @@ _Py_SetFileSystemEncoding(const char *encoding, const char *errors)
}
+/* --- Py_SetStandardStreamEncoding() ----------------------------- */
+
/* Helper to allow an embedding application to override the normal
* mechanism that attempts to figure out an appropriate IO encoding
*/
@@ -282,6 +423,68 @@ _Py_ClearStandardStreamEncoding(void)
}
+/* --- Py_GetArgcArgv() ------------------------------------------- */
+
+/* For Py_GetArgcArgv(); set by _Py_SetArgcArgv() */
+static int orig_argc = 0;
+static wchar_t **orig_argv = NULL;
+
+
+void
+_Py_ClearArgcArgv(void)
+{
+ PyMemAllocatorEx old_alloc;
+ _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
+ _Py_wstrlist_clear(orig_argc, orig_argv);
+ orig_argc = 0;
+ orig_argv = NULL;
+
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+}
+
+
+int
+_Py_SetArgcArgv(int argc, wchar_t * const *argv)
+{
+ int res;
+
+ PyMemAllocatorEx old_alloc;
+ _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+
+ wchar_t **argv_copy = _Py_wstrlist_copy(argc, argv);
+ if (argv_copy != NULL) {
+ _Py_ClearArgcArgv();
+ orig_argc = argc;
+ orig_argv = argv_copy;
+ res = 0;
+ }
+ else {
+ res = -1;
+ }
+
+ PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
+ return res;
+}
+
+
+/* Make the *original* argc/argv available to other modules.
+ This is rare, but it is needed by the secureware extension. */
+void
+Py_GetArgcArgv(int *argc, wchar_t ***argv)
+{
+ *argc = orig_argc;
+ *argv = orig_argv;
+}
+
+
+/* --- _PyCoreConfig ---------------------------------------------- */
+
+#define DECODE_LOCALE_ERR(NAME, LEN) \
+ (((LEN) == -2) \
+ ? _Py_INIT_USER_ERR("cannot decode " NAME) \
+ : _Py_INIT_NO_MEMORY())
+
/* Free memory allocated in config, but don't clear all attributes */
void
_PyCoreConfig_Clear(_PyCoreConfig *config)
@@ -1469,6 +1672,60 @@ _PyCoreConfig_Read(_PyCoreConfig *config)
}
+static void
+config_init_stdio(const _PyCoreConfig *config)
+{
+#if defined(MS_WINDOWS) || defined(__CYGWIN__)
+ /* don't translate newlines (\r\n <=> \n) */
+ _setmode(fileno(stdin), O_BINARY);
+ _setmode(fileno(stdout), O_BINARY);
+ _setmode(fileno(stderr), O_BINARY);
+#endif
+
+ if (!config->buffered_stdio) {
+#ifdef HAVE_SETVBUF
+ setvbuf(stdin, (char *)NULL, _IONBF, BUFSIZ);
+ setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
+ setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
+#else /* !HAVE_SETVBUF */
+ setbuf(stdin, (char *)NULL);
+ setbuf(stdout, (char *)NULL);
+ setbuf(stderr, (char *)NULL);
+#endif /* !HAVE_SETVBUF */
+ }
+ else if (config->interactive) {
+#ifdef MS_WINDOWS
+ /* Doesn't have to have line-buffered -- use unbuffered */
+ /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */
+ setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
+#else /* !MS_WINDOWS */
+#ifdef HAVE_SETVBUF
+ setvbuf(stdin, (char *)NULL, _IOLBF, BUFSIZ);
+ setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
+#endif /* HAVE_SETVBUF */
+#endif /* !MS_WINDOWS */
+ /* Leave stderr alone - it should be unbuffered anyway. */
+ }
+}
+
+
+/* Write the configuration:
+
+ - coerce the LC_CTYPE locale (PEP 538)
+ - UTF-8 mode (PEP 540)
+ - set Py_xxx global configuration variables
+ - initialize C standard streams (stdin, stdout, stderr) */
+void
+_PyCoreConfig_Write(const _PyCoreConfig *config)
+{
+ if (config->coerce_c_locale) {
+ _Py_CoerceLegacyLocale(config->coerce_c_locale_warn);
+ }
+ _PyCoreConfig_SetGlobalConfig(config);
+ config_init_stdio(config);
+}
+
+
PyObject *
_PyCoreConfig_AsDict(const _PyCoreConfig *config)
{
@@ -1586,3 +1843,681 @@ fail:
#undef SET_ITEM_WSTR
#undef SET_ITEM_WSTRLIST
}
+
+
+/* --- _PyCmdline ------------------------------------------------- */
+
+typedef struct {
+ const _PyArgv *args;
+ wchar_t **argv;
+ int nwarnoption; /* Number of -W command line options */
+ wchar_t **warnoptions; /* Command line -W options */
+ int nenv_warnoption; /* Number of PYTHONWARNINGS environment variables */
+ wchar_t **env_warnoptions; /* PYTHONWARNINGS environment variables */
+ int print_help; /* -h, -? options */
+ int print_version; /* -V option */
+} _PyCmdline;
+
+
+static void
+cmdline_clear(_PyCmdline *cmdline)
+{
+ _Py_wstrlist_clear(cmdline->nwarnoption, cmdline->warnoptions);
+ cmdline->nwarnoption = 0;
+ cmdline->warnoptions = NULL;
+
+ _Py_wstrlist_clear(cmdline->nenv_warnoption, cmdline->env_warnoptions);
+ cmdline->nenv_warnoption = 0;
+ cmdline->env_warnoptions = NULL;
+
+ if (cmdline->args->use_bytes_argv && cmdline->argv != NULL) {
+ _Py_wstrlist_clear(cmdline->args->argc, cmdline->argv);
+ }
+ cmdline->argv = NULL;
+}
+
+
+static _PyInitError
+cmdline_decode_argv(_PyCmdline *cmdline)
+{
+ assert(cmdline->argv == NULL);
+
+ const _PyArgv *args = cmdline->args;
+
+ if (args->use_bytes_argv) {
+ /* +1 for a the NULL terminator */
+ size_t size = sizeof(wchar_t*) * (args->argc + 1);
+ wchar_t** argv = (wchar_t **)PyMem_RawMalloc(size);
+ if (argv == NULL) {
+ return _Py_INIT_NO_MEMORY();
+ }
+
+ for (int i = 0; i < args->argc; i++) {
+ size_t len;
+ wchar_t *arg = Py_DecodeLocale(args->bytes_argv[i], &len);
+ if (arg == NULL) {
+ _Py_wstrlist_clear(i, argv);
+ return DECODE_LOCALE_ERR("command line arguments",
+ (Py_ssize_t)len);
+ }
+ argv[i] = arg;
+ }
+ argv[args->argc] = NULL;
+
+ cmdline->argv = argv;
+ }
+ else {
+ cmdline->argv = args->wchar_argv;
+ }
+ return _Py_INIT_OK();
+}
+
+
+/* --- _PyCoreConfig command line parser -------------------------- */
+
+/* Parse the command line arguments */
+static _PyInitError
+config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
+ int *need_usage)
+{
+ _PyInitError err;
+ _PyOS_ResetGetOpt();
+ do {
+ int longindex = -1;
+ int c = _PyOS_GetOpt(cmdline->args->argc, cmdline->argv, PROGRAM_OPTS,
+ longoptions, &longindex);
+ if (c == EOF) {
+ break;
+ }
+
+ if (c == 'c') {
+ /* -c is the last option; following arguments
+ that look like options are left for the
+ command to interpret. */
+ size_t len = wcslen(_PyOS_optarg) + 1 + 1;
+ wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len);
+ if (command == NULL) {
+ return _Py_INIT_NO_MEMORY();
+ }
+ memcpy(command, _PyOS_optarg, (len - 2) * sizeof(wchar_t));
+ command[len - 2] = '\n';
+ command[len - 1] = 0;
+ config->run_command = command;
+ break;
+ }
+
+ if (c == 'm') {
+ /* -m is the last option; following arguments
+ that look like options are left for the
+ module to interpret. */
+ config->run_module = _PyMem_RawWcsdup(_PyOS_optarg);
+ if (config->run_module == NULL) {
+ return _Py_INIT_NO_MEMORY();
+ }
+ break;
+ }
+
+ switch (c) {
+ case 0:
+ // Handle long option.
+ assert(longindex == 0); // Only one long option now.
+ if (!wcscmp(_PyOS_optarg, L"always")) {
+ config->_check_hash_pycs_mode = "always";
+ } else if (!wcscmp(_PyOS_optarg, L"never")) {
+ config->_check_hash_pycs_mode = "never";
+ } else if (!wcscmp(_PyOS_optarg, L"default")) {
+ config->_check_hash_pycs_mode = "default";
+ } else {
+ fprintf(stderr, "--check-hash-based-pycs must be one of "
+ "'default', 'always', or 'never'\n");
+ *need_usage = 1;
+ return _Py_INIT_OK();
+ }
+ break;
+
+ case 'b':
+ config->bytes_warning++;
+ break;
+
+ case 'd':
+ config->parser_debug++;
+ break;
+
+ case 'i':
+ config->inspect++;
+ config->interactive++;
+ break;
+
+ case 'I':
+ config->isolated++;
+ break;
+
+ /* case 'J': reserved for Jython */
+
+ case 'O':
+ config->optimization_level++;
+ break;
+
+ case 'B':
+ config->write_bytecode = 0;
+ break;
+
+ case 's':
+ config->user_site_directory = 0;
+ break;
+
+ case 'S':
+ config->site_import = 0;
+ break;
+
+ case 'E':
+ config->use_environment = 0;
+ break;
+
+ case 't':
+ /* ignored for backwards compatibility */
+ break;
+
+ case 'u':
+ config->buffered_stdio = 0;
+ break;
+
+ case 'v':
+ config->verbose++;
+ break;
+
+ case 'x':
+ config->skip_source_first_line = 1;
+ break;
+
+ case 'h':
+ case '?':
+ cmdline->print_help++;
+ break;
+
+ case 'V':
+ cmdline->print_version++;
+ break;
+
+ case 'W':
+ err = _Py_wstrlist_append(&cmdline->nwarnoption,
+ &cmdline->warnoptions,
+ _PyOS_optarg);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+ break;
+
+ case 'X':
+ err = _Py_wstrlist_append(&config->nxoption,
+ &config->xoptions,
+ _PyOS_optarg);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+ break;
+
+ case 'q':
+ config->quiet++;
+ break;
+
+ case 'R':
+ config->use_hash_seed = 0;
+ break;
+
+ /* This space reserved for other options */
+
+ default:
+ /* unknown argument: parsing failed */
+ *need_usage = 1;
+ return _Py_INIT_OK();
+ }
+ } while (1);
+
+ if (config->run_command == NULL && config->run_module == NULL
+ && _PyOS_optind < cmdline->args->argc
+ && wcscmp(cmdline->argv[_PyOS_optind], L"-") != 0)
+ {
+ config->run_filename = _PyMem_RawWcsdup(cmdline->argv[_PyOS_optind]);
+ if (config->run_filename == NULL) {
+ return _Py_INIT_NO_MEMORY();
+ }
+ }
+
+ if (config->run_command != NULL || config->run_module != NULL) {
+ /* Backup _PyOS_optind */
+ _PyOS_optind--;
+ }
+
+ /* -c and -m options are exclusive */
+ assert(!(config->run_command != NULL && config->run_module != NULL));
+
+ return _Py_INIT_OK();
+}
+
+
+#ifdef MS_WINDOWS
+# define WCSTOK wcstok_s
+#else
+# define WCSTOK wcstok
+#endif
+
+/* Get warning options from PYTHONWARNINGS environment variable. */
+static _PyInitError
+cmdline_init_env_warnoptions(_PyCmdline *cmdline, const _PyCoreConfig *config)
+{
+ wchar_t *env;
+ int res = _PyCoreConfig_GetEnvDup(config, &env,
+ L"PYTHONWARNINGS", "PYTHONWARNINGS");
+ if (res < 0) {
+ return DECODE_LOCALE_ERR("PYTHONWARNINGS", res);
+ }
+
+ if (env == NULL) {
+ return _Py_INIT_OK();
+ }
+
+
+ wchar_t *warning, *context = NULL;
+ for (warning = WCSTOK(env, L",", &context);
+ warning != NULL;
+ warning = WCSTOK(NULL, L",", &context))
+ {
+ _PyInitError err = _Py_wstrlist_append(&cmdline->nenv_warnoption,
+ &cmdline->env_warnoptions,
+ warning);
+ if (_Py_INIT_FAILED(err)) {
+ PyMem_RawFree(env);
+ return err;
+ }
+ }
+ PyMem_RawFree(env);
+ return _Py_INIT_OK();
+}
+
+
+static _PyInitError
+config_init_program(_PyCoreConfig *config, const _PyCmdline *cmdline)
+{
+ wchar_t *program;
+ if (cmdline->args->argc >= 1 && cmdline->argv != NULL) {
+ program = cmdline->argv[0];
+ }
+ else {
+ program = L"";
+ }
+ config->program = _PyMem_RawWcsdup(program);
+ if (config->program == NULL) {
+ return _Py_INIT_NO_MEMORY();
+ }
+
+ return _Py_INIT_OK();
+}
+
+
+static _PyInitError
+config_add_warnings_optlist(_PyCoreConfig *config,
+ int len, wchar_t * const *options)
+{
+ for (int i = 0; i < len; i++) {
+ _PyInitError err = _Py_wstrlist_append(&config->nwarnoption,
+ &config->warnoptions,
+ options[i]);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+ }
+ return _Py_INIT_OK();
+}
+
+
+static _PyInitError
+config_init_warnoptions(_PyCoreConfig *config, const _PyCmdline *cmdline)
+{
+ _PyInitError err;
+
+ assert(config->nwarnoption == 0);
+
+ /* The priority order for warnings configuration is (highest precedence
+ * first):
+ *
+ * - the BytesWarning filter, if needed ('-b', '-bb')
+ * - any '-W' command line options; then
+ * - the 'PYTHONWARNINGS' environment variable; then
+ * - the dev mode filter ('-X dev', 'PYTHONDEVMODE'); then
+ * - any implicit filters added by _warnings.c/warnings.py
+ *
+ * All settings except the last are passed to the warnings module via
+ * the `sys.warnoptions` list. Since the warnings module works on the basis
+ * of "the most recently added filter will be checked first", we add
+ * the lowest precedence entries first so that later entries override them.
+ */
+
+ if (config->dev_mode) {
+ err = _Py_wstrlist_append(&config->nwarnoption,
+ &config->warnoptions,
+ L"default");
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+ }
+
+ err = config_add_warnings_optlist(config,
+ cmdline->nenv_warnoption,
+ cmdline->env_warnoptions);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
+ err = config_add_warnings_optlist(config,
+ cmdline->nwarnoption,
+ cmdline->warnoptions);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
+ /* If the bytes_warning_flag isn't set, bytesobject.c and bytearrayobject.c
+ * don't even try to emit a warning, so we skip setting the filter in that
+ * case.
+ */
+ if (config->bytes_warning) {
+ wchar_t *filter;
+ if (config->bytes_warning> 1) {
+ filter = L"error::BytesWarning";
+ }
+ else {
+ filter = L"default::BytesWarning";
+ }
+ err = _Py_wstrlist_append(&config->nwarnoption,
+ &config->warnoptions,
+ filter);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+ }
+ return _Py_INIT_OK();
+}
+
+
+static _PyInitError
+config_init_argv(_PyCoreConfig *config, const _PyCmdline *cmdline)
+{
+ /* Copy argv to be able to modify it (to force -c/-m) */
+ int argc = cmdline->args->argc - _PyOS_optind;
+ wchar_t **argv;
+
+ if (argc <= 0 || cmdline->argv == NULL) {
+ /* Ensure at least one (empty) argument is seen */
+ static wchar_t *empty_argv[1] = {L""};
+ argc = 1;
+ argv = _Py_wstrlist_copy(1, empty_argv);
+ }
+ else {
+ argv = _Py_wstrlist_copy(argc, &cmdline->argv[_PyOS_optind]);
+ }
+
+ if (argv == NULL) {
+ return _Py_INIT_NO_MEMORY();
+ }
+
+ wchar_t *arg0 = NULL;
+ if (config->run_command != NULL) {
+ /* Force sys.argv[0] = '-c' */
+ arg0 = L"-c";
+ }
+ else if (config->run_module != NULL) {
+ /* Force sys.argv[0] = '-m'*/
+ arg0 = L"-m";
+ }
+ if (arg0 != NULL) {
+ arg0 = _PyMem_RawWcsdup(arg0);
+ if (arg0 == NULL) {
+ _Py_wstrlist_clear(argc, argv);
+ return _Py_INIT_NO_MEMORY();
+ }
+
+ assert(argc >= 1);
+ PyMem_RawFree(argv[0]);
+ argv[0] = arg0;
+ }
+
+ config->argc = argc;
+ config->argv = argv;
+ return _Py_INIT_OK();
+}
+
+
+static void
+config_usage(int error, const wchar_t* program)
+{
+ FILE *f = error ? stderr : stdout;
+
+ fprintf(f, usage_line, program);
+ if (error)
+ fprintf(f, "Try `python -h' for more information.\n");
+ else {
+ fputs(usage_1, f);
+ fputs(usage_2, f);
+ fputs(usage_3, f);
+ fprintf(f, usage_4, (wint_t)DELIM);
+ fprintf(f, usage_5, (wint_t)DELIM, PYTHONHOMEHELP);
+ fputs(usage_6, f);
+ }
+}
+
+
+/* Parse command line options and environment variables. */
+static _PyInitError
+config_from_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline)
+{
+ int need_usage = 0;
+ _PyInitError err;
+
+ err = config_init_program(config, cmdline);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
+ err = config_parse_cmdline(config, cmdline, &need_usage);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
+ if (need_usage) {
+ config_usage(1, config->program);
+ return _Py_INIT_EXIT(2);
+ }
+
+ if (cmdline->print_help) {
+ config_usage(0, config->program);
+ return _Py_INIT_EXIT(0);
+ }
+
+ if (cmdline->print_version) {
+ printf("Python %s\n",
+ (cmdline->print_version >= 2) ? Py_GetVersion() : PY_VERSION);
+ return _Py_INIT_EXIT(0);
+ }
+
+ err = config_init_argv(config, cmdline);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
+ err = _PyCoreConfig_Read(config);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
+ if (config->use_environment) {
+ err = cmdline_init_env_warnoptions(cmdline, config);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+ }
+
+ err = config_init_warnoptions(config, cmdline);
+ if (_Py_INIT_FAILED(err)) {
+ return err;
+ }
+
+ if (_Py_SetArgcArgv(cmdline->args->argc, cmdline->argv) < 0) {
+ return _Py_INIT_NO_MEMORY();
+ }
+ return _Py_INIT_OK();
+}
+
+
+static _PyInitError
+config_read_from_argv_impl(_PyCoreConfig *config, const _PyArgv *args)
+{
+ _PyInitError err;
+
+ _PyCmdline cmdline;
+ memset(&cmdline, 0, sizeof(cmdline));
+ cmdline.args = args;
+
+ err = cmdline_decode_argv(&cmdline);
+ if (_Py_INIT_FAILED(err)) {
+ goto done;
+ }
+
+ err = config_from_cmdline(config, &cmdline);
+ if (_Py_INIT_FAILED(err)) {
+ goto done;
+ }
+ err = _Py_INIT_OK();
+
+done:
+ cmdline_clear(&cmdline);
+ return err;
+}
+
+
+/* Read the configuration into _PyCoreConfig and initialize the LC_CTYPE
+ locale: enable UTF-8 mode (PEP 540) and/or coerce the C locale (PEP 538).
+
+ Read the configuration from:
+
+ * Command line arguments
+ * Environment variables
+ * Py_xxx global configuration variables */
+_PyInitError
+_PyCoreConfig_ReadFromArgv(_PyCoreConfig *config, const _PyArgv *args)
+{
+ _PyInitError err;
+ int init_utf8_mode = Py_UTF8Mode;
+#ifdef MS_WINDOWS
+ int init_legacy_encoding = Py_LegacyWindowsFSEncodingFlag;
+#endif
+ _PyCoreConfig save_config = _PyCoreConfig_INIT;
+ int locale_coerced = 0;
+ int loops = 0;
+ char *init_ctype_locale = NULL;
+
+ /* copy LC_CTYPE locale */
+ const char *loc = setlocale(LC_CTYPE, NULL);
+ if (loc == NULL) {
+ err = _Py_INIT_ERR("failed to LC_CTYPE locale");
+ goto done;
+ }
+ init_ctype_locale = _PyMem_RawStrdup(loc);
+ if (init_ctype_locale == NULL) {
+ err = _Py_INIT_NO_MEMORY();
+ goto done;
+ }
+
+ if (_PyCoreConfig_Copy(&save_config, config) < 0) {
+ err = _Py_INIT_NO_MEMORY();
+ goto done;
+ }
+
+ /* Set LC_CTYPE to the user preferred locale */
+ _Py_SetLocaleFromEnv(LC_CTYPE);
+
+ while (1) {
+ int utf8_mode = config->utf8_mode;
+ int encoding_changed = 0;
+
+ /* Watchdog to prevent an infinite loop */
+ loops++;
+ if (loops == 3) {
+ err = _Py_INIT_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
+
+ err = config_read_from_argv_impl(config, args);
+ if (_Py_INIT_FAILED(err)) {
+ goto done;
+ }
+ if (locale_coerced) {
+ config->coerce_c_locale = 1;
+ }
+
+ /* 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.
+ */
+ 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;
+ if (_PyCoreConfig_Copy(config, &save_config) < 0) {
+ err = _Py_INIT_NO_MEMORY();
+ goto done;
+ }
+ 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 */
+ }
+ err = _Py_INIT_OK();
+
+done:
+ if (init_ctype_locale != NULL) {
+ setlocale(LC_CTYPE, init_ctype_locale);
+ }
+ _PyCoreConfig_Clear(&save_config);
+ Py_UTF8Mode = init_utf8_mode ;
+#ifdef MS_WINDOWS
+ Py_LegacyWindowsFSEncodingFlag = init_legacy_encoding;
+#endif
+ return err;
+}