Skip to content

bpo-32030: Add _PyPathConfig_ComputeArgv0() #4845

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Include/pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ PyAPI_FUNC(wchar_t *) Py_GetPath(void);
#ifdef Py_BUILD_CORE
PyAPI_FUNC(_PyInitError) _PyPathConfig_Init(
const _PyMainInterpreterConfig *main_config);
PyAPI_FUNC(PyObject*) _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv);
#endif
PyAPI_FUNC(void) Py_SetPath(const wchar_t *);
#ifdef MS_WINDOWS
Expand Down
6 changes: 0 additions & 6 deletions Include/sysmodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@ PyAPI_FUNC(int) _PySys_SetObjectId(_Py_Identifier *key, PyObject *);

PyAPI_FUNC(void) PySys_SetArgv(int, wchar_t **);
PyAPI_FUNC(void) PySys_SetArgvEx(int, wchar_t **, int);
#ifdef Py_BUILD_CORE
PyAPI_FUNC(_PyInitError) _PySys_SetArgvWithError(
int argc,
wchar_t **argv,
int updatepath);
#endif
PyAPI_FUNC(void) PySys_SetPath(const wchar_t *);

PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...)
Expand Down
107 changes: 91 additions & 16 deletions Modules/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,13 @@ typedef struct {
#endif
} _Py_CommandLineDetails;

/* FIXME: temporary structure until sys module configuration can be moved
into _PyMainInterpreterConfig */
typedef struct {
PyObject *argv; /* sys.argv list */
PyObject *path0; /* path0: if set, it is prepended to sys.path */
} _PySysConfig;

/* Structure used by Py_Main() to pass data to subfunctions */
typedef struct {
/* Exit status ("exit code") */
Expand All @@ -419,6 +426,7 @@ typedef struct {
int stdin_is_interactive;
_PyCoreConfig core_config;
_PyMainInterpreterConfig config;
_PySysConfig sys_config;
_Py_CommandLineDetails cmdline;
PyObject *main_importer_path;
/* non-zero if filename, command (-c) or module (-m) is set
Expand Down Expand Up @@ -492,6 +500,8 @@ pymain_free_pymain(_PyMain *pymain)
pymain_optlist_clear(&pymain->env_warning_options);
Py_CLEAR(pymain->main_importer_path);

Py_CLEAR(pymain->sys_config.argv);
Py_CLEAR(pymain->sys_config.path0);
}

static void
Expand All @@ -510,26 +520,20 @@ pymain_free(_PyMain *pymain)
static int
pymain_run_main_from_importer(_PyMain *pymain)
{
PyObject *sys_path0 = pymain->main_importer_path;
PyObject *sys_path;
int sts;

/* Assume sys_path0 has already been checked by pymain_get_importer(),
* so put it in sys.path[0] and import __main__ */
sys_path = PySys_GetObject("path");
PyObject *sys_path = PySys_GetObject("path");
if (sys_path == NULL) {
PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path");
goto error;
}

sts = PyList_Insert(sys_path, 0, sys_path0);
if (sts) {
sys_path0 = NULL;
if (PyList_Insert(sys_path, 0, pymain->main_importer_path)) {
goto error;
}

sts = pymain_run_module(L"__main__", 0);
return sts != 0;
int sts = pymain_run_module(L"__main__", 0);
return (sts != 0);

error:
Py_CLEAR(pymain->main_importer_path);
Expand Down Expand Up @@ -1082,8 +1086,36 @@ pymain_header(_PyMain *pymain)
}


static PyObject *
pymain_create_argv_list(int argc, wchar_t **argv)
{
if (argc <= 0 || argv == NULL) {
/* Ensure at least one (empty) argument is seen */
static wchar_t *empty_argv[1] = {L""};
argv = empty_argv;
argc = 1;
}

PyObject *av = PyList_New(argc);
if (av == NULL) {
return NULL;
}

for (int i = 0; i < argc; i++) {
PyObject *v = PyUnicode_FromWideChar(argv[i], -1);
if (v == NULL) {
Py_DECREF(av);
return NULL;
}
PyList_SET_ITEM(av, i, v);
}
return av;
}


/* Create sys.argv list and maybe also path0 */
static int
pymain_set_sys_argv(_PyMain *pymain)
pymain_compute_argv(_PyMain *pymain)
{
_Py_CommandLineDetails *cmdline = &pymain->cmdline;

Expand Down Expand Up @@ -1112,6 +1144,14 @@ pymain_set_sys_argv(_PyMain *pymain)
argv2[0] = L"-m";
}

/* Create sys.argv list */
pymain->sys_config.argv = pymain_create_argv_list(argc2, argv2);
if (pymain->sys_config.argv == NULL) {
pymain->err = _Py_INIT_ERR("failed to create sys.argv");
goto error;
}

/* Need to update sys.path[0]? */
int update_path;
if (pymain->main_importer_path != NULL) {
/* Let pymain_run_main_from_importer() adjust sys.path[0] later */
Expand All @@ -1121,16 +1161,48 @@ pymain_set_sys_argv(_PyMain *pymain)
update_path = (Py_IsolatedFlag == 0);
}

/* Set sys.argv. If '-c' and '-m' options are not used in the command line
/* If '-c' and '-m' options are not used in the command line
and update_path is non-zero, prepend argv[0] to sys.path. If argv[0] is
a symlink, use the real path. */
_PyInitError err = _PySys_SetArgvWithError(argc2, argv2, update_path);
if (_Py_INIT_FAILED(err)) {
pymain->err = err;
if (update_path) {
pymain->sys_config.path0 = _PyPathConfig_ComputeArgv0(argc2, argv2);
if (pymain->sys_config.path0 == NULL) {
pymain->err = _Py_INIT_NO_MEMORY();
goto error;
}
}
PyMem_RawFree(argv2);
return 0;

error:
return -1;
}

static int
pymain_set_sys_argv(_PyMain *pymain)
{
/* Set sys.argv */
if (PySys_SetObject("argv", pymain->sys_config.argv) != 0) {
pymain->err = _Py_INIT_ERR("can't assign sys.argv");
return -1;
}
Py_CLEAR(pymain->sys_config.argv);

if (pymain->sys_config.path0 != NULL) {
/* Prepend path0 to sys.path */
PyObject *sys_path = PySys_GetObject("path");
if (sys_path == NULL) {
pymain->err = _Py_INIT_ERR("can't get sys.path");
return -1;
}

if (PyList_Insert(sys_path, 0, pymain->sys_config.path0) < 0) {
pymain->err = _Py_INIT_ERR("sys.path.insert(0, path0) failed");
return -1;
}
Py_CLEAR(pymain->sys_config.path0);
}

PyMem_RawFree(argv2);
return 0;
}

Expand Down Expand Up @@ -1822,6 +1894,9 @@ pymain_init_python(_PyMain *pymain)
Currently, PySys_SetArgvEx() can still modify sys.path and so must be
called after _Py_InitializeMainInterpreter() which calls
_PyPathConfig_Init(). */
if (pymain_compute_argv(pymain) < 0) {
return -1;
}
if (pymain_set_sys_argv(pymain) < 0) {
return -1;
}
Expand Down
98 changes: 98 additions & 0 deletions Python/pathconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,104 @@ Py_GetProgramName(void)
}


#define _HAVE_SCRIPT_ARGUMENT(argc, argv) \
(argc > 0 && argv0 != NULL && \
wcscmp(argv0, L"-c") != 0 && wcscmp(argv0, L"-m") != 0)

/* Compute argv[0] which will be prepended to sys.argv */
PyObject*
_PyPathConfig_ComputeArgv0(int argc, wchar_t **argv)
{
wchar_t *argv0;
wchar_t *p = NULL;
Py_ssize_t n = 0;
#ifdef HAVE_READLINK
wchar_t link[MAXPATHLEN+1];
wchar_t argv0copy[2*MAXPATHLEN+1];
int nr = 0;
#endif
#if defined(HAVE_REALPATH)
wchar_t fullpath[MAXPATHLEN];
#elif defined(MS_WINDOWS)
wchar_t fullpath[MAX_PATH];
#endif


argv0 = argv[0];

#ifdef HAVE_READLINK
if (_HAVE_SCRIPT_ARGUMENT(argc, argv))
nr = _Py_wreadlink(argv0, link, MAXPATHLEN);
if (nr > 0) {
/* It's a symlink */
link[nr] = '\0';
if (link[0] == SEP)
argv0 = link; /* Link to absolute path */
else if (wcschr(link, SEP) == NULL)
; /* Link without path */
else {
/* Must join(dirname(argv0), link) */
wchar_t *q = wcsrchr(argv0, SEP);
if (q == NULL)
argv0 = link; /* argv0 without path */
else {
/* Must make a copy, argv0copy has room for 2 * MAXPATHLEN */
wcsncpy(argv0copy, argv0, MAXPATHLEN);
q = wcsrchr(argv0copy, SEP);
wcsncpy(q+1, link, MAXPATHLEN);
q[MAXPATHLEN + 1] = L'\0';
argv0 = argv0copy;
}
}
}
#endif /* HAVE_READLINK */

#if SEP == '\\'
/* Special case for Microsoft filename syntax */
if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) {
wchar_t *q;
#if defined(MS_WINDOWS)
/* Replace the first element in argv with the full path. */
wchar_t *ptemp;
if (GetFullPathNameW(argv0,
Py_ARRAY_LENGTH(fullpath),
fullpath,
&ptemp)) {
argv0 = fullpath;
}
#endif
p = wcsrchr(argv0, SEP);
/* Test for alternate separator */
q = wcsrchr(p ? p : argv0, '/');
if (q != NULL)
p = q;
if (p != NULL) {
n = p + 1 - argv0;
if (n > 1 && p[-1] != ':')
n--; /* Drop trailing separator */
}
}
#else /* All other filename syntaxes */
if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) {
#if defined(HAVE_REALPATH)
if (_Py_wrealpath(argv0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
argv0 = fullpath;
}
#endif
p = wcsrchr(argv0, SEP);
}
if (p != NULL) {
n = p + 1 - argv0;
#if SEP == '/' /* Special case for Unix filename syntax */
if (n > 1)
n--; /* Drop trailing separator */
#endif /* Unix */
}
#endif /* All others */

return PyUnicode_FromWideChar(argv0, n);
}

#ifdef __cplusplus
}
#endif
Loading