mirror of
https://github.com/python/cpython.git
synced 2026-07-25 03:12:54 -04:00
1b41c7b722
* Check for signals more often. Previously, a pending exception could be removed by PyErr_Clear(). * Only call _PyInterpreterState_SetNotRunningMain() if _PyInterpreterState_SetRunningMain() has been called. * Add pymain_error() and pyrun_error(): write the error message to sys.stderr instead of the C stream stderr. * Convert _PyPathConfig_UpdateGlobal() PyStatus error to an exception. * Simplify pymain_run_startup(): avoid strerror() which is decoded from the wrong encoding. Instead display the exception, Py_fopen() raises an OSError with the path object (and can raise other exceptions). * Add pymain_set_path0() function. * Add _PySys_FormatV() function.
947 lines
22 KiB
C
947 lines
22 KiB
C
/* Python interpreter main program */
|
|
|
|
#include "Python.h"
|
|
#include "pycore_call.h" // _PyObject_CallNoArgs()
|
|
#include "pycore_fileutils.h" // struct _Py_stat_struct
|
|
#include "pycore_import.h" // _PyImport_Fini2()
|
|
#include "pycore_initconfig.h" // _PyArgv
|
|
#include "pycore_interp.h" // _PyInterpreterState.sysdict
|
|
#include "pycore_long.h" // _PyLong_GetOne()
|
|
#include "pycore_pathconfig.h" // _PyPathConfig_ComputeSysPath0()
|
|
#include "pycore_pylifecycle.h" // _Py_PreInitializeFromPyArgv()
|
|
#include "pycore_pystate.h" // _PyInterpreterState_GET()
|
|
#include "pycore_pythonrun.h" // _PyRun_AnyFile()
|
|
#include "pycore_sysmodule.h" // _PySys_FormatV()
|
|
#include "pycore_tuple.h" // _PyTuple_FromPair
|
|
#include "pycore_unicodeobject.h" // _PyUnicode_Dedent()
|
|
|
|
/* Includes for exit_sigint() */
|
|
#include <stdio.h> // perror()
|
|
#ifdef HAVE_SIGNAL_H
|
|
# include <signal.h> // SIGINT
|
|
#endif
|
|
#if defined(HAVE_GETPID) && defined(HAVE_UNISTD_H)
|
|
# include <unistd.h> // getpid()
|
|
#endif
|
|
#ifdef MS_WINDOWS
|
|
# include <windows.h> // STATUS_CONTROL_C_EXIT
|
|
#endif
|
|
/* End of includes for exit_sigint() */
|
|
|
|
#define COPYRIGHT \
|
|
"Type \"help\", \"copyright\", \"credits\" or \"license\" " \
|
|
"for more information."
|
|
|
|
/* --- pymain_init() ---------------------------------------------- */
|
|
|
|
static PyStatus
|
|
pymain_init(const _PyArgv *args)
|
|
{
|
|
PyStatus status;
|
|
|
|
status = _PyRuntime_Initialize();
|
|
if (_PyStatus_EXCEPTION(status)) {
|
|
return status;
|
|
}
|
|
|
|
PyPreConfig preconfig;
|
|
PyPreConfig_InitPythonConfig(&preconfig);
|
|
|
|
status = _Py_PreInitializeFromPyArgv(&preconfig, args);
|
|
if (_PyStatus_EXCEPTION(status)) {
|
|
return status;
|
|
}
|
|
|
|
PyConfig config;
|
|
PyConfig_InitPythonConfig(&config);
|
|
|
|
/* pass NULL as the config: config is read from command line arguments,
|
|
environment variables, configuration files */
|
|
if (args->use_bytes_argv) {
|
|
status = PyConfig_SetBytesArgv(&config, args->argc, args->bytes_argv);
|
|
}
|
|
else {
|
|
status = PyConfig_SetArgv(&config, args->argc, args->wchar_argv);
|
|
}
|
|
if (_PyStatus_EXCEPTION(status)) {
|
|
goto done;
|
|
}
|
|
|
|
status = Py_InitializeFromConfig(&config);
|
|
if (_PyStatus_EXCEPTION(status)) {
|
|
goto done;
|
|
}
|
|
status = _PyStatus_OK();
|
|
|
|
done:
|
|
PyConfig_Clear(&config);
|
|
return status;
|
|
}
|
|
|
|
|
|
/* --- pymain_run_python() ---------------------------------------- */
|
|
|
|
static void
|
|
pymain_error_format(const char *format, ...)
|
|
{
|
|
va_list vargs;
|
|
va_start(vargs, format);
|
|
|
|
PySys_WriteStderr("python: ");
|
|
_PySys_FormatV(&_Py_ID(stderr), stderr, format, vargs);
|
|
PySys_WriteStderr("\n");
|
|
|
|
va_end(vargs);
|
|
}
|
|
|
|
// See also pyrun_error()
|
|
static void
|
|
pymain_error(const char *msg)
|
|
{
|
|
PySys_FormatStderr("python: %s\n", msg);
|
|
}
|
|
|
|
static int
|
|
pymain_check_signals(void)
|
|
{
|
|
return Py_MakePendingCalls();
|
|
}
|
|
|
|
/* Non-zero if filename, command (-c) or module (-m) is set
|
|
on the command line */
|
|
static inline int config_run_code(const PyConfig *config)
|
|
{
|
|
return (config->run_command != NULL
|
|
|| config->run_filename != NULL
|
|
|| config->run_module != NULL);
|
|
}
|
|
|
|
|
|
/* Return non-zero if stdin is a TTY or if -i command line option is used */
|
|
static int
|
|
stdin_is_interactive(const PyConfig *config)
|
|
{
|
|
return (isatty(fileno(stdin)) || config->interactive);
|
|
}
|
|
|
|
|
|
/* Display the current Python exception and return an exitcode */
|
|
static int
|
|
pymain_err_print(int *exitcode_p)
|
|
{
|
|
int exitcode;
|
|
if (_Py_HandleSystemExitAndKeyboardInterrupt(&exitcode)) {
|
|
*exitcode_p = exitcode;
|
|
return 1;
|
|
}
|
|
|
|
PyErr_Print();
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_exit_err_print(void)
|
|
{
|
|
int exitcode = 1;
|
|
pymain_err_print(&exitcode);
|
|
return exitcode;
|
|
}
|
|
|
|
|
|
// If filename is a package (ex: directory or ZIP file) which contains
|
|
// __main__.py, main_importer_path is set to filename and will be prepended to
|
|
// sys.path.
|
|
//
|
|
// Otherwise, main_importer_path is left unchanged.
|
|
//
|
|
// Write an exitcode into *exitcode and return 1 if we have to exit Python.
|
|
// Return 0 otherwise.
|
|
static int
|
|
pymain_get_importer(const PyConfig *config, PyObject **importer_p,
|
|
int *exitcode)
|
|
{
|
|
const wchar_t *filename = config->run_filename;
|
|
if (filename == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
PyObject *sys_path0 = PyUnicode_FromWideChar(filename, -1);
|
|
if (sys_path0 == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
PyObject *importer = PyImport_GetImporter(sys_path0);
|
|
if (importer == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
if (importer == Py_None) {
|
|
Py_DECREF(sys_path0);
|
|
Py_DECREF(importer);
|
|
return 0;
|
|
}
|
|
|
|
Py_DECREF(importer);
|
|
*importer_p = sys_path0;
|
|
return 0;
|
|
|
|
error:
|
|
Py_XDECREF(sys_path0);
|
|
|
|
pymain_error("Failed checking if argv[0] is an import path entry:");
|
|
return pymain_err_print(exitcode);
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_sys_path_add_path0(PyObject *path0)
|
|
{
|
|
PyObject *sys_path;
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
|
PyObject *sysdict = interp->sysdict;
|
|
if (sysdict != NULL) {
|
|
sys_path = PyDict_GetItemWithError(sysdict, &_Py_ID(path));
|
|
if (sys_path == NULL && PyErr_Occurred()) {
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
sys_path = NULL;
|
|
}
|
|
if (sys_path == NULL) {
|
|
PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path");
|
|
return -1;
|
|
}
|
|
|
|
if (PyList_Insert(sys_path, 0, path0)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void
|
|
pymain_header(const PyConfig *config)
|
|
{
|
|
if (config->quiet) {
|
|
return;
|
|
}
|
|
|
|
if (!config->verbose && (config_run_code(config) || !stdin_is_interactive(config))) {
|
|
return;
|
|
}
|
|
|
|
fprintf(stderr, "Python %s on %s\n", Py_GetVersion(), Py_GetPlatform());
|
|
if (config->site_import) {
|
|
fprintf(stderr, "%s\n", COPYRIGHT);
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_import_readline(const PyConfig *config)
|
|
{
|
|
if (pymain_check_signals() < 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (config->isolated) {
|
|
return 0;
|
|
}
|
|
if (!config->inspect && config_run_code(config)) {
|
|
return 0;
|
|
}
|
|
if (!isatty(fileno(stdin))) {
|
|
return 0;
|
|
}
|
|
|
|
PyObject *mod = PyImport_ImportModule("readline");
|
|
if (mod == NULL) {
|
|
PyErr_Clear();
|
|
}
|
|
else {
|
|
Py_DECREF(mod);
|
|
}
|
|
|
|
mod = PyImport_ImportModule("rlcompleter");
|
|
if (mod == NULL) {
|
|
PyErr_Clear();
|
|
}
|
|
else {
|
|
Py_DECREF(mod);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_run_command(wchar_t *command)
|
|
{
|
|
PyObject *unicode, *bytes;
|
|
|
|
unicode = PyUnicode_FromWideChar(command, -1);
|
|
if (unicode == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
if (PySys_Audit("cpython.run_command", "O", unicode) < 0) {
|
|
return pymain_exit_err_print();
|
|
}
|
|
|
|
Py_SETREF(unicode, _PyUnicode_Dedent(unicode));
|
|
if (unicode == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
bytes = PyUnicode_AsUTF8String(unicode);
|
|
Py_DECREF(unicode);
|
|
if (bytes == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
PyCompilerFlags cf = _PyCompilerFlags_INIT;
|
|
cf.cf_flags |= PyCF_IGNORE_COOKIE;
|
|
PyObject *result = NULL;
|
|
PyObject *string_obj = PyUnicode_FromString("<string>");
|
|
if (string_obj != NULL) {
|
|
result = _PyRun_SimpleString(PyBytes_AsString(bytes),
|
|
string_obj, &cf);
|
|
Py_DECREF(string_obj);
|
|
}
|
|
Py_DECREF(bytes);
|
|
if (result == NULL) {
|
|
return pymain_exit_err_print();
|
|
}
|
|
return 0;
|
|
|
|
error:
|
|
pymain_error("Unable to decode the command from the command line:");
|
|
return pymain_exit_err_print();
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_run_pyrepl(int pythonstartup)
|
|
{
|
|
int exitcode = 0;
|
|
PyObject *console = NULL;
|
|
PyObject *empty_tuple = NULL;
|
|
PyObject *kwargs = NULL;
|
|
PyObject *console_result = NULL;
|
|
PyObject *main_module = NULL;
|
|
|
|
PyObject *pyrepl = PyImport_ImportModule("_pyrepl.main");
|
|
if (pyrepl == NULL) {
|
|
pymain_error("Could not import _pyrepl.main");
|
|
goto error;
|
|
}
|
|
|
|
console = PyObject_GetAttrString(pyrepl, "interactive_console");
|
|
if (console == NULL) {
|
|
pymain_error("Could not access _pyrepl.main.interactive_console");
|
|
goto error;
|
|
}
|
|
|
|
empty_tuple = PyTuple_New(0);
|
|
if (empty_tuple == NULL) {
|
|
goto error;
|
|
}
|
|
kwargs = PyDict_New();
|
|
if (kwargs == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
main_module = PyImport_AddModuleRef("__main__");
|
|
if (main_module == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
PyObject *value = pythonstartup ? Py_True : Py_False;
|
|
if (PyDict_SetItemString(kwargs, "mainmodule", main_module)
|
|
|| PyDict_SetItemString(kwargs, "pythonstartup", value))
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
console_result = PyObject_Call(console, empty_tuple, kwargs);
|
|
if (console_result == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
done:
|
|
Py_XDECREF(console_result);
|
|
Py_XDECREF(kwargs);
|
|
Py_XDECREF(empty_tuple);
|
|
Py_XDECREF(console);
|
|
Py_XDECREF(pyrepl);
|
|
Py_XDECREF(main_module);
|
|
return exitcode;
|
|
|
|
error:
|
|
exitcode = pymain_exit_err_print();
|
|
goto done;
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_run_module(const wchar_t *modname, int set_argv0)
|
|
{
|
|
int exitcode = 0;
|
|
PyObject *module = NULL;
|
|
PyObject *runmodule = NULL;
|
|
PyObject *runargs = NULL;
|
|
PyObject *result = NULL;
|
|
|
|
if (PySys_Audit("cpython.run_module", "u", modname) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
runmodule = PyImport_ImportModuleAttrString("runpy",
|
|
"_run_module_as_main");
|
|
if (runmodule == NULL) {
|
|
pymain_error("Could not import runpy._run_module_as_main");
|
|
goto error;
|
|
}
|
|
|
|
module = PyUnicode_FromWideChar(modname, -1);
|
|
if (module == NULL) {
|
|
pymain_error("Could not convert module name to unicode");
|
|
goto error;
|
|
}
|
|
|
|
runargs = _PyTuple_FromPair(module, set_argv0 ? Py_True : Py_False);
|
|
if (runargs == NULL) {
|
|
pymain_error("Could not create arguments "
|
|
"for runpy._run_module_as_main");
|
|
goto error;
|
|
}
|
|
|
|
result = PyObject_Call(runmodule, runargs, NULL);
|
|
if (result == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
done:
|
|
Py_XDECREF(module);
|
|
Py_XDECREF(runmodule);
|
|
Py_XDECREF(runargs);
|
|
Py_XDECREF(result);
|
|
return exitcode;
|
|
|
|
error:
|
|
exitcode = pymain_exit_err_print();
|
|
goto done;
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_run_file_obj(PyObject *filename, int skip_source_first_line)
|
|
{
|
|
if (PySys_Audit("cpython.run_file", "O", filename) < 0) {
|
|
return pymain_exit_err_print();
|
|
}
|
|
|
|
FILE *fp = Py_fopen(filename, "rb");
|
|
if (fp == NULL) {
|
|
pymain_error_format("can't open file %R:", filename);
|
|
pymain_exit_err_print();
|
|
return 2;
|
|
}
|
|
|
|
if (skip_source_first_line) {
|
|
int ch;
|
|
/* Push back first newline so line numbers remain the same */
|
|
while ((ch = getc(fp)) != EOF) {
|
|
if (ch == '\n') {
|
|
(void)ungetc(ch, fp);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct _Py_stat_struct sb;
|
|
if (_Py_fstat_noraise(fileno(fp), &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
|
pymain_error_format("%R is a directory, cannot continue",
|
|
filename);
|
|
fclose(fp);
|
|
return 1;
|
|
}
|
|
|
|
if (pymain_check_signals() < 0) {
|
|
fclose(fp);
|
|
return pymain_exit_err_print();
|
|
}
|
|
|
|
/* _PyRun_AnyFile(closeit=1) calls fclose(fp) before running code */
|
|
PyCompilerFlags cf = _PyCompilerFlags_INIT;
|
|
PyObject *result = _PyRun_AnyFile(fp, filename, 1, &cf);
|
|
if (result == NULL) {
|
|
return pymain_exit_err_print();
|
|
}
|
|
Py_DECREF(result);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
pymain_run_file(const PyConfig *config)
|
|
{
|
|
PyObject *filename = PyUnicode_FromWideChar(config->run_filename, -1);
|
|
if (filename == NULL) {
|
|
return pymain_exit_err_print();
|
|
}
|
|
|
|
int exitcode = pymain_run_file_obj(filename, config->skip_source_first_line);
|
|
Py_XDECREF(filename);
|
|
return exitcode;
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_run_startup(PyConfig *config, int *exitcode)
|
|
{
|
|
int ret = 0;
|
|
PyObject *startup = NULL;
|
|
|
|
if (!config->use_environment) {
|
|
goto done;
|
|
}
|
|
#ifdef MS_WINDOWS
|
|
const wchar_t *env = _wgetenv(L"PYTHONSTARTUP");
|
|
if (env == NULL || env[0] == L'\0') {
|
|
goto done;
|
|
}
|
|
|
|
startup = PyUnicode_FromWideChar(env, -1);
|
|
if (startup == NULL) {
|
|
goto error;
|
|
}
|
|
#else
|
|
const char *env = _Py_GetEnv(config->use_environment, "PYTHONSTARTUP");
|
|
if (env == NULL) {
|
|
goto done;
|
|
}
|
|
|
|
startup = PyUnicode_DecodeFSDefault(env);
|
|
if (startup == NULL) {
|
|
goto error;
|
|
}
|
|
#endif
|
|
if (PySys_Audit("cpython.run_startup", "O", startup) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
FILE *fp = Py_fopen(startup, "r");
|
|
if (fp == NULL) {
|
|
pymain_error("Could not open PYTHONSTARTUP");
|
|
goto error;
|
|
}
|
|
|
|
PyCompilerFlags cf = _PyCompilerFlags_INIT;
|
|
PyObject *result = _PyRun_SimpleFile(fp, startup, 0, &cf);
|
|
fclose(fp);
|
|
if (result == NULL) {
|
|
goto error;
|
|
}
|
|
Py_DECREF(result);
|
|
|
|
done:
|
|
Py_XDECREF(startup);
|
|
return ret;
|
|
|
|
error:
|
|
ret = pymain_err_print(exitcode);
|
|
goto done;
|
|
}
|
|
|
|
|
|
/* Write an exitcode into *exitcode and return 1 if we have to exit Python.
|
|
Return 0 otherwise. */
|
|
static int
|
|
pymain_run_interactive_hook(int *exitcode)
|
|
{
|
|
PyObject *hook;
|
|
if (PySys_GetOptionalAttrString("__interactivehook__", &hook) < 0) {
|
|
goto error;
|
|
}
|
|
if (hook == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) {
|
|
Py_DECREF(hook);
|
|
goto error;
|
|
}
|
|
|
|
PyObject *result = _PyObject_CallNoArgs(hook);
|
|
Py_DECREF(hook);
|
|
if (result == NULL) {
|
|
goto error;
|
|
}
|
|
Py_DECREF(result);
|
|
return 0;
|
|
|
|
error:
|
|
pymain_error("Failed calling sys.__interactivehook__:");
|
|
return pymain_err_print(exitcode);
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_set_inspect(PyConfig *config, int inspect, int *exitcode)
|
|
{
|
|
PyObject *value = PyLong_FromLong(inspect);
|
|
if (value == NULL || PyConfig_Set("inspect", value) < 0) {
|
|
Py_XDECREF(value);
|
|
pymain_error("Could not set the inspect flag");
|
|
return pymain_err_print(exitcode);
|
|
}
|
|
else {
|
|
assert(config->inspect == inspect);
|
|
}
|
|
Py_XDECREF(value);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
_pymain_run_repl(PyConfig *config, int startup)
|
|
{
|
|
if (pymain_check_signals() < 0) {
|
|
goto error;
|
|
}
|
|
|
|
if (PySys_Audit("cpython.run_stdin", NULL) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
if (isatty(fileno(stdin))
|
|
&& !_Py_GetEnv(config->use_environment, "PYTHON_BASIC_REPL"))
|
|
{
|
|
PyObject *pyrepl = PyImport_ImportModule("_pyrepl");
|
|
if (pyrepl != NULL) {
|
|
int exitcode = pymain_run_pyrepl(startup);
|
|
Py_DECREF(pyrepl);
|
|
return exitcode;
|
|
}
|
|
|
|
if (!PyErr_ExceptionMatches(PyExc_ModuleNotFoundError)) {
|
|
pymain_error("Could not import _pyrepl.main");
|
|
goto error;
|
|
}
|
|
PyErr_Clear();
|
|
}
|
|
|
|
PyCompilerFlags cf = _PyCompilerFlags_INIT;
|
|
PyObject *result = NULL;
|
|
PyObject *stdin_obj = PyUnicode_FromString("<stdin>");
|
|
if (stdin_obj != NULL) {
|
|
result = _PyRun_AnyFile(stdin, stdin_obj, 0, &cf);
|
|
Py_DECREF(stdin_obj);
|
|
}
|
|
if (result == NULL) {
|
|
goto error;
|
|
}
|
|
Py_DECREF(result);
|
|
return 0;
|
|
|
|
error:
|
|
return pymain_exit_err_print();
|
|
}
|
|
|
|
static int
|
|
pymain_run_stdin(PyConfig *config)
|
|
{
|
|
if (stdin_is_interactive(config)) {
|
|
// do exit on SystemExit
|
|
int exitcode;
|
|
if (pymain_set_inspect(config, 0, &exitcode)) {
|
|
return exitcode;
|
|
}
|
|
|
|
if (pymain_run_startup(config, &exitcode)) {
|
|
return exitcode;
|
|
}
|
|
|
|
if (pymain_run_interactive_hook(&exitcode)) {
|
|
return exitcode;
|
|
}
|
|
}
|
|
|
|
return _pymain_run_repl(config, 0);
|
|
}
|
|
|
|
|
|
static void
|
|
pymain_repl(PyConfig *config, int *exitcode)
|
|
{
|
|
/* Check this environment variable at the end, to give programs the
|
|
opportunity to set it from Python. */
|
|
if (!config->inspect && _Py_GetEnv(config->use_environment, "PYTHONINSPECT")) {
|
|
if (pymain_set_inspect(config, 1, exitcode)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!(config->inspect && stdin_is_interactive(config) && config_run_code(config))) {
|
|
return;
|
|
}
|
|
|
|
if (pymain_set_inspect(config, 0, exitcode)) {
|
|
return;
|
|
}
|
|
if (pymain_run_interactive_hook(exitcode)) {
|
|
return;
|
|
}
|
|
|
|
*exitcode = _pymain_run_repl(config, 1);
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_set_path0(PyObject *main_importer_path)
|
|
{
|
|
PyConfig *config = (PyConfig *)_Py_GetConfig();
|
|
|
|
PyObject *path0 = NULL;
|
|
if (main_importer_path != NULL) {
|
|
path0 = Py_NewRef(main_importer_path);
|
|
}
|
|
else if (!config->safe_path) {
|
|
int res = _PyPathConfig_ComputeSysPath0(&config->argv, &path0);
|
|
if (res < 0) {
|
|
return -1;
|
|
}
|
|
else if (res == 0) {
|
|
Py_CLEAR(path0);
|
|
}
|
|
}
|
|
|
|
if (path0 == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
// XXX Apply config->sys_path_0 in init_interp_main(). We have
|
|
// to be sure to get readline/rlcompleter imported at the correct time.
|
|
wchar_t *wstr = PyUnicode_AsWideCharString(path0, NULL);
|
|
if (wstr == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
PyStatus status = PyConfig_SetString(config, &config->sys_path_0, wstr);
|
|
PyMem_Free(wstr);
|
|
if (_PyStatus_EXCEPTION(status)) {
|
|
_PyErr_SetFromPyStatus(status);
|
|
goto error;
|
|
}
|
|
|
|
int res = pymain_sys_path_add_path0(path0);
|
|
Py_DECREF(path0);
|
|
|
|
return res;
|
|
|
|
error:
|
|
Py_DECREF(path0);
|
|
return -1;
|
|
}
|
|
|
|
|
|
static void
|
|
pymain_run_python(int *exitcode)
|
|
{
|
|
int set_running_main = 0;
|
|
|
|
PyObject *main_importer_path = NULL;
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
|
/* pymain_repl() and pymain_run_stdin() modify the config */
|
|
PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp);
|
|
|
|
/* ensure path config is written into global variables */
|
|
PyStatus status = _PyPathConfig_UpdateGlobal(config);
|
|
if (_PyStatus_EXCEPTION(status)) {
|
|
_PyErr_SetFromPyStatus(status);
|
|
goto error;
|
|
}
|
|
|
|
// XXX Calculate config->sys_path_0 in getpath.py.
|
|
// The tricky part is that we can't check the path importers yet
|
|
// at that point.
|
|
assert(config->sys_path_0 == NULL);
|
|
|
|
if (pymain_get_importer(config, &main_importer_path, exitcode)) {
|
|
return;
|
|
}
|
|
|
|
// import readline and rlcompleter before script dir is added to sys.path
|
|
if (pymain_import_readline(config) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
if (pymain_set_path0(main_importer_path) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
pymain_header(config);
|
|
|
|
_PyInterpreterState_SetRunningMain(interp);
|
|
set_running_main = 1;
|
|
assert(!PyErr_Occurred());
|
|
|
|
if (pymain_check_signals() < 0) {
|
|
goto error;
|
|
}
|
|
|
|
if (config->run_command) {
|
|
*exitcode = pymain_run_command(config->run_command);
|
|
}
|
|
else if (config->run_module) {
|
|
*exitcode = pymain_run_module(config->run_module, 1);
|
|
}
|
|
else if (main_importer_path != NULL) {
|
|
*exitcode = pymain_run_module(L"__main__", 0);
|
|
}
|
|
else if (config->run_filename != NULL) {
|
|
*exitcode = pymain_run_file(config);
|
|
}
|
|
else {
|
|
*exitcode = pymain_run_stdin(config);
|
|
}
|
|
|
|
if (pymain_check_signals() < 0) {
|
|
goto error;
|
|
}
|
|
|
|
pymain_repl(config, exitcode);
|
|
goto done;
|
|
|
|
error:
|
|
*exitcode = pymain_exit_err_print();
|
|
|
|
done:
|
|
if (set_running_main) {
|
|
_PyInterpreterState_SetNotRunningMain(interp);
|
|
}
|
|
Py_XDECREF(main_importer_path);
|
|
}
|
|
|
|
|
|
/* --- pymain_main() ---------------------------------------------- */
|
|
|
|
static void
|
|
pymain_free(void)
|
|
{
|
|
_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_ClearArgcArgv();
|
|
_PyRuntime_Finalize();
|
|
}
|
|
|
|
|
|
static int
|
|
exit_sigint(void)
|
|
{
|
|
/* 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(HAVE_KILL) && !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 */
|
|
return STATUS_CONTROL_C_EXIT;
|
|
#else
|
|
return SIGINT + 128;
|
|
#endif /* !MS_WINDOWS */
|
|
}
|
|
|
|
|
|
static void _Py_NO_RETURN
|
|
pymain_exit_error(PyStatus status)
|
|
{
|
|
if (_PyStatus_IS_EXIT(status)) {
|
|
/* If it's an error rather than a regular exit, leave Python runtime
|
|
alive: Py_ExitStatusException() uses the current exception and use
|
|
sys.stdout in this case. */
|
|
pymain_free();
|
|
}
|
|
Py_ExitStatusException(status);
|
|
}
|
|
|
|
|
|
int
|
|
Py_RunMain(void)
|
|
{
|
|
int exitcode = 0;
|
|
|
|
_PyRuntime.signals.unhandled_keyboard_interrupt = 0;
|
|
|
|
pymain_run_python(&exitcode);
|
|
|
|
if (Py_FinalizeEx() < 0) {
|
|
/* Value unlikely to be confused with a non-error exit status or
|
|
other special meaning */
|
|
exitcode = 120;
|
|
}
|
|
|
|
pymain_free();
|
|
|
|
if (_PyRuntime.signals.unhandled_keyboard_interrupt) {
|
|
exitcode = exit_sigint();
|
|
}
|
|
|
|
return exitcode;
|
|
}
|
|
|
|
|
|
static int
|
|
pymain_main(_PyArgv *args)
|
|
{
|
|
PyStatus status = pymain_init(args);
|
|
if (_PyStatus_IS_EXIT(status)) {
|
|
pymain_free();
|
|
return status.exitcode;
|
|
}
|
|
if (_PyStatus_EXCEPTION(status)) {
|
|
pymain_exit_error(status);
|
|
}
|
|
|
|
return Py_RunMain();
|
|
}
|
|
|
|
|
|
int
|
|
Py_Main(int argc, wchar_t **argv)
|
|
{
|
|
_PyArgv args = {
|
|
.argc = argc,
|
|
.use_bytes_argv = 0,
|
|
.bytes_argv = NULL,
|
|
.wchar_argv = argv};
|
|
return pymain_main(&args);
|
|
}
|
|
|
|
|
|
int
|
|
Py_BytesMain(int argc, char **argv)
|
|
{
|
|
_PyArgv args = {
|
|
.argc = argc,
|
|
.use_bytes_argv = 1,
|
|
.bytes_argv = argv,
|
|
.wchar_argv = NULL};
|
|
return pymain_main(&args);
|
|
}
|