Skip to content

Commit fa15376

Browse files
authored
bpo-36301: Add _PyPreCmdline internal API (GH-12458)
_PyCoreConfig_ReadFromArgv() now reuses the code parsing command line options from preconfig.c.
1 parent abbdd1f commit fa15376

File tree

3 files changed

+99
-47
lines changed

3 files changed

+99
-47
lines changed

Include/internal/pycore_coreconfig.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,30 @@ extern "C" {
99
#endif
1010

1111

12+
/* --- _PyPreCmdline ------------------------------------------------- */
13+
14+
typedef struct {
15+
_PyWstrList argv;
16+
_PyWstrList xoptions; /* "-X value" option */
17+
int use_environment; /* -E option */
18+
int isolated; /* -I option */
19+
} _PyPreCmdline;
20+
21+
#define _PyPreCmdline_INIT \
22+
(_PyPreCmdline){ \
23+
.use_environment = -1, \
24+
.isolated = -1}
25+
/* Note: _PyPreCmdline_INIT sets other fields to 0/NULL */
26+
27+
PyAPI_FUNC(void) _PyPreCmdline_Clear(_PyPreCmdline *cmdline);
28+
PyAPI_FUNC(_PyInitError) _PyPreCmdline_Init(_PyPreCmdline *cmdline,
29+
const _PyArgv *args);
30+
PyAPI_FUNC(_PyInitError) _PyPreCmdline_Read(_PyPreCmdline *cmdline);
31+
PyAPI_FUNC(void) _PyPreCmdline_SetPreConfig(
32+
const _PyPreCmdline *cmdline,
33+
_PyPreConfig *config);
34+
35+
1236
/* --- _PyWstrList ------------------------------------------------ */
1337

1438
#ifndef NDEBUG

Python/coreconfig.c

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,7 +1658,7 @@ _PyCoreConfig_AsDict(const _PyCoreConfig *config)
16581658
/* --- _PyCmdline ------------------------------------------------- */
16591659

16601660
typedef struct {
1661-
_PyWstrList argv;
1661+
_PyPreCmdline precmdline;
16621662
_PyWstrList warnoptions; /* Command line -W options */
16631663
_PyWstrList env_warnoptions; /* PYTHONWARNINGS environment variables */
16641664
int print_help; /* -h, -? options */
@@ -1669,9 +1669,9 @@ typedef struct {
16691669
static void
16701670
cmdline_clear(_PyCmdline *cmdline)
16711671
{
1672+
_PyPreCmdline_Clear(&cmdline->precmdline);
16721673
_PyWstrList_Clear(&cmdline->warnoptions);
16731674
_PyWstrList_Clear(&cmdline->env_warnoptions);
1674-
_PyWstrList_Clear(&cmdline->argv);
16751675
}
16761676

16771677

@@ -1682,10 +1682,12 @@ static _PyInitError
16821682
config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
16831683
int *need_usage)
16841684
{
1685+
const _PyWstrList *argv = &cmdline->precmdline.argv;
1686+
16851687
_PyOS_ResetGetOpt();
16861688
do {
16871689
int longindex = -1;
1688-
int c = _PyOS_GetOpt(cmdline->argv.length, cmdline->argv.items, &longindex);
1690+
int c = _PyOS_GetOpt(argv->length, argv->items, &longindex);
16891691
if (c == EOF) {
16901692
break;
16911693
}
@@ -1754,6 +1756,7 @@ config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
17541756

17551757
case 'E':
17561758
case 'I':
1759+
case 'X':
17571760
/* option handled by _PyPreConfig_ReadFromArgv() */
17581761
break;
17591762

@@ -1806,12 +1809,6 @@ config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
18061809
}
18071810
break;
18081811

1809-
case 'X':
1810-
if (_PyWstrList_Append(&config->xoptions, _PyOS_optarg) < 0) {
1811-
return _Py_INIT_NO_MEMORY();
1812-
}
1813-
break;
1814-
18151812
case 'q':
18161813
config->quiet++;
18171814
break;
@@ -1830,11 +1827,11 @@ config_parse_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
18301827
} while (1);
18311828

18321829
if (config->run_command == NULL && config->run_module == NULL
1833-
&& _PyOS_optind < cmdline->argv.length
1834-
&& wcscmp(cmdline->argv.items[_PyOS_optind], L"-") != 0
1830+
&& _PyOS_optind < argv->length
1831+
&& wcscmp(argv->items[_PyOS_optind], L"-") != 0
18351832
&& config->run_filename == NULL)
18361833
{
1837-
config->run_filename = _PyMem_RawWcsdup(cmdline->argv.items[_PyOS_optind]);
1834+
config->run_filename = _PyMem_RawWcsdup(argv->items[_PyOS_optind]);
18381835
if (config->run_filename == NULL) {
18391836
return _Py_INIT_NO_MEMORY();
18401837
}
@@ -1892,9 +1889,10 @@ cmdline_init_env_warnoptions(_PyCmdline *cmdline, const _PyCoreConfig *config)
18921889
static _PyInitError
18931890
config_init_program(_PyCoreConfig *config, const _PyCmdline *cmdline)
18941891
{
1892+
const _PyWstrList *argv = &cmdline->precmdline.argv;
18951893
wchar_t *program;
1896-
if (cmdline->argv.length >= 1) {
1897-
program = cmdline->argv.items[0];
1894+
if (argv->length >= 1) {
1895+
program = argv->items[0];
18981896
}
18991897
else {
19001898
program = L"";
@@ -1965,24 +1963,25 @@ config_init_warnoptions(_PyCoreConfig *config, const _PyCmdline *cmdline)
19651963
static _PyInitError
19661964
config_init_argv(_PyCoreConfig *config, const _PyCmdline *cmdline)
19671965
{
1968-
_PyWstrList wargv = _PyWstrList_INIT;
1966+
const _PyWstrList *cmdline_argv = &cmdline->precmdline.argv;
1967+
_PyWstrList config_argv = _PyWstrList_INIT;
19691968

19701969
/* Copy argv to be able to modify it (to force -c/-m) */
1971-
if (cmdline->argv.length <= _PyOS_optind) {
1970+
if (cmdline_argv->length <= _PyOS_optind) {
19721971
/* Ensure at least one (empty) argument is seen */
1973-
if (_PyWstrList_Append(&wargv, L"") < 0) {
1972+
if (_PyWstrList_Append(&config_argv, L"") < 0) {
19741973
return _Py_INIT_NO_MEMORY();
19751974
}
19761975
}
19771976
else {
19781977
_PyWstrList slice;
1979-
slice.length = cmdline->argv.length - _PyOS_optind;
1980-
slice.items = &cmdline->argv.items[_PyOS_optind];
1981-
if (_PyWstrList_Copy(&wargv, &slice) < 0) {
1978+
slice.length = cmdline_argv->length - _PyOS_optind;
1979+
slice.items = &cmdline_argv->items[_PyOS_optind];
1980+
if (_PyWstrList_Copy(&config_argv, &slice) < 0) {
19821981
return _Py_INIT_NO_MEMORY();
19831982
}
19841983
}
1985-
assert(wargv.length >= 1);
1984+
assert(config_argv.length >= 1);
19861985

19871986
wchar_t *arg0 = NULL;
19881987
if (config->run_command != NULL) {
@@ -1996,16 +1995,16 @@ config_init_argv(_PyCoreConfig *config, const _PyCmdline *cmdline)
19961995
if (arg0 != NULL) {
19971996
arg0 = _PyMem_RawWcsdup(arg0);
19981997
if (arg0 == NULL) {
1999-
_PyWstrList_Clear(&wargv);
1998+
_PyWstrList_Clear(&config_argv);
20001999
return _Py_INIT_NO_MEMORY();
20012000
}
20022001

2003-
PyMem_RawFree(wargv.items[0]);
2004-
wargv.items[0] = arg0;
2002+
PyMem_RawFree(config_argv.items[0]);
2003+
config_argv.items[0] = arg0;
20052004
}
20062005

20072006
_PyWstrList_Clear(&config->argv);
2008-
config->argv = wargv;
2007+
config->argv = config_argv;
20092008
return _Py_INIT_OK();
20102009
}
20112010

@@ -2046,6 +2045,16 @@ config_from_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
20462045
}
20472046
}
20482047

2048+
err = _PyPreCmdline_Read(&cmdline->precmdline);
2049+
if (_Py_INIT_FAILED(err)) {
2050+
return err;
2051+
}
2052+
2053+
_PyPreCmdline_SetPreConfig(&cmdline->precmdline, &config->preconfig);
2054+
if (_PyWstrList_Extend(&config->xoptions, &cmdline->precmdline.xoptions) < 0) {
2055+
return _Py_INIT_NO_MEMORY();
2056+
}
2057+
20492058
err = config_parse_cmdline(config, cmdline, &need_usage);
20502059
if (_Py_INIT_FAILED(err)) {
20512060
return err;
@@ -2089,7 +2098,8 @@ config_from_cmdline(_PyCoreConfig *config, _PyCmdline *cmdline,
20892098
return err;
20902099
}
20912100

2092-
if (_Py_SetArgcArgv(cmdline->argv.length, cmdline->argv.items) < 0) {
2101+
const _PyWstrList *argv = &cmdline->precmdline.argv;
2102+
if (_Py_SetArgcArgv(argv->length, argv->items) < 0) {
20932103
return _Py_INIT_NO_MEMORY();
20942104
}
20952105
return _Py_INIT_OK();
@@ -2107,10 +2117,9 @@ _PyCoreConfig_ReadFromArgv(_PyCoreConfig *config, const _PyArgv *args,
21072117
{
21082118
_PyInitError err;
21092119

2110-
_PyCmdline cmdline;
2111-
memset(&cmdline, 0, sizeof(cmdline));
2120+
_PyCmdline cmdline = {.precmdline = _PyPreCmdline_INIT};
21122121

2113-
err = _PyArgv_AsWstrList(args, &cmdline.argv);
2122+
err = _PyPreCmdline_Init(&cmdline.precmdline, args);
21142123
if (_Py_INIT_FAILED(err)) {
21152124
goto done;
21162125
}

Python/preconfig.c

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -102,20 +102,21 @@ _PyArgv_AsWstrList(const _PyArgv *args, _PyWstrList *list)
102102

103103
/* --- _PyPreCmdline ------------------------------------------------- */
104104

105-
typedef struct {
106-
_PyWstrList argv;
107-
_PyWstrList xoptions; /* -X options */
108-
} _PyPreCmdline;
109-
110-
111-
static void
112-
precmdline_clear(_PyPreCmdline *cmdline)
105+
void
106+
_PyPreCmdline_Clear(_PyPreCmdline *cmdline)
113107
{
114108
_PyWstrList_Clear(&cmdline->argv);
115109
_PyWstrList_Clear(&cmdline->xoptions);
116110
}
117111

118112

113+
_PyInitError
114+
_PyPreCmdline_Init(_PyPreCmdline *cmdline, const _PyArgv *args)
115+
{
116+
return _PyArgv_AsWstrList(args, &cmdline->argv);
117+
}
118+
119+
119120
/* --- _PyPreConfig ----------------------------------------------- */
120121

121122
void
@@ -520,6 +521,21 @@ _PyPreConfig_Read(_PyPreConfig *config)
520521
}
521522

522523

524+
void
525+
_PyPreCmdline_SetPreConfig(const _PyPreCmdline *cmdline, _PyPreConfig *config)
526+
{
527+
#define COPY_ATTR(ATTR) \
528+
if (cmdline->ATTR != -1) { \
529+
config->ATTR = cmdline->ATTR; \
530+
}
531+
532+
COPY_ATTR(use_environment);
533+
COPY_ATTR(isolated);
534+
535+
#undef COPY_ATTR
536+
}
537+
538+
523539
int
524540
_PyPreConfig_AsDict(const _PyPreConfig *config, PyObject *dict)
525541
{
@@ -567,28 +583,30 @@ _PyPreConfig_AsDict(const _PyPreConfig *config, PyObject *dict)
567583

568584

569585
/* Parse the command line arguments */
570-
static _PyInitError
571-
preconfig_parse_cmdline(_PyPreConfig *config, _PyPreCmdline *cmdline)
586+
_PyInitError
587+
_PyPreCmdline_Read(_PyPreCmdline *cmdline)
572588
{
589+
_PyWstrList *argv = &cmdline->argv;
590+
573591
_PyOS_ResetGetOpt();
574592
/* Don't log parsing errors into stderr here: _PyCoreConfig_ReadFromArgv()
575593
is responsible for that */
576594
_PyOS_opterr = 0;
577595
do {
578596
int longindex = -1;
579-
int c = _PyOS_GetOpt(cmdline->argv.length, cmdline->argv.items, &longindex);
597+
int c = _PyOS_GetOpt(argv->length, argv->items, &longindex);
580598

581599
if (c == EOF || c == 'c' || c == 'm') {
582600
break;
583601
}
584602

585603
switch (c) {
586604
case 'E':
587-
config->use_environment = 0;
605+
cmdline->use_environment = 0;
588606
break;
589607

590608
case 'I':
591-
config->isolated++;
609+
cmdline->isolated = 1;
592610
break;
593611

594612
case 'X':
@@ -615,27 +633,28 @@ preconfig_from_argv(_PyPreConfig *config, const _PyArgv *args)
615633
{
616634
_PyInitError err;
617635

618-
_PyPreCmdline cmdline;
619-
memset(&cmdline, 0, sizeof(cmdline));
636+
_PyPreCmdline cmdline = _PyPreCmdline_INIT;
620637

621-
err = _PyArgv_AsWstrList(args, &cmdline.argv);
638+
err = _PyPreCmdline_Init(&cmdline, args);
622639
if (_Py_INIT_FAILED(err)) {
623640
goto done;
624641
}
625642

626-
err = preconfig_parse_cmdline(config, &cmdline);
643+
err = _PyPreCmdline_Read(&cmdline);
627644
if (_Py_INIT_FAILED(err)) {
628645
goto done;
629646
}
630647

648+
_PyPreCmdline_SetPreConfig(&cmdline, config);
649+
631650
err = preconfig_read(config, &cmdline);
632651
if (_Py_INIT_FAILED(err)) {
633652
goto done;
634653
}
635654
err = _Py_INIT_OK();
636655

637656
done:
638-
precmdline_clear(&cmdline);
657+
_PyPreCmdline_Clear(&cmdline);
639658
return err;
640659
}
641660

0 commit comments

Comments
 (0)