Skip to content

Commit 74f6568

Browse files
authored
bpo-36301: Add _PyWstrList structure (GH-12343)
Replace messy _Py_wstrlist_xxx() functions with a new clean _PyWstrList structure and new _PyWstrList_xxx() functions. Changes: * Add _PyCoreConfig.use_module_search_paths to decide if _PyCoreConfig.module_search_paths should be computed or not, to support empty search path list. * _PyWstrList_Clear() sets length to 0 and items to NULL, whereas _Py_wstrlist_clear() only freed memory. * _PyWstrList_Append() returns an int, whereas _Py_wstrlist_append() returned _PyInitError. * _PyWstrList uses Py_ssize_t for the length, instead of int. * Replace (int, wchar_t**) with _PyWstrList in: * _PyPreConfig * _PyCoreConfig * _PyPreCmdline * _PyCmdline * Replace "int orig_argv; wchar_t **orig_argv;" with "_PyWstrList orig_argv". * _PyCmdline and _PyPreCmdline now also copy wchar_argv. * Rename _PyArgv_Decode() to _PyArgv_AsWstrList(). * PySys_SetArgvEx() now pass the fixed (argc, argv) to _PyPathConfig_ComputeArgv0() (don't pass negative argc or NULL argv). * _PyOS_GetOpt() uses Py_ssize_t
1 parent 86082c2 commit 74f6568

File tree

11 files changed

+303
-345
lines changed

11 files changed

+303
-345
lines changed

‎Include/cpython/coreconfig.h‎

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ typedef struct {
4646
#define _Py_INIT_FAILED(err) \
4747
(err.msg != NULL || err.exitcode != -1)
4848

49+
/* --- _PyWstrList ------------------------------------------------ */
50+
51+
typedef struct {
52+
/* If length is greater than zero, items must be non-NULL
53+
and all items strings must be non-NULL */
54+
Py_ssize_t length;
55+
wchar_t **items;
56+
} _PyWstrList;
57+
58+
#define _PyWstrList_INIT (_PyWstrList){.length = 0, .items = NULL}
59+
60+
4961
/* --- _PyPreConfig ----------------------------------------------- */
5062

5163
typedef struct {
@@ -162,29 +174,24 @@ typedef struct {
162174
char *filesystem_encoding;
163175
char *filesystem_errors;
164176

165-
wchar_t *pycache_prefix; /* PYTHONPYCACHEPREFIX, -X pycache_prefix=PATH */
166-
167-
wchar_t *program_name; /* Program name, see also Py_GetProgramName() */
168-
int argc; /* Number of command line arguments,
169-
-1 means unset */
170-
wchar_t **argv; /* Command line arguments */
171-
wchar_t *program; /* argv[0] or "" */
172-
173-
int nxoption; /* Number of -X options */
174-
wchar_t **xoptions; /* -X options */
175-
176-
int nwarnoption; /* Number of warnings options */
177-
wchar_t **warnoptions; /* Warnings options */
177+
wchar_t *pycache_prefix; /* PYTHONPYCACHEPREFIX, -X pycache_prefix=PATH */
178+
wchar_t *program_name; /* Program name, see also Py_GetProgramName() */
179+
_PyWstrList argv; /* Command line arguments */
180+
wchar_t *program; /* argv[0] or "" */
181+
_PyWstrList xoptions; /* Command line -X options */
182+
_PyWstrList warnoptions; /* Warnings options */
178183

179184
/* Path configuration inputs */
180185
wchar_t *module_search_path_env; /* PYTHONPATH environment variable */
181186
wchar_t *home; /* PYTHONHOME environment variable,
182187
see also Py_SetPythonHome(). */
183188

184189
/* Path configuration outputs */
185-
int nmodule_search_path; /* Number of sys.path paths,
186-
-1 means unset */
187-
wchar_t **module_search_paths; /* sys.path paths */
190+
int use_module_search_paths; /* If non-zero, use module_search_paths */
191+
_PyWstrList module_search_paths; /* sys.path paths. Computed if
192+
use_module_search_paths is equal
193+
to zero. */
194+
188195
wchar_t *executable; /* sys.executable */
189196
wchar_t *prefix; /* sys.prefix */
190197
wchar_t *base_prefix; /* sys.base_prefix */
@@ -366,8 +373,7 @@ typedef struct {
366373
.use_hash_seed = -1, \
367374
.faulthandler = -1, \
368375
.tracemalloc = -1, \
369-
.argc = -1, \
370-
.nmodule_search_path = -1, \
376+
.use_module_search_paths = 0, \
371377
.site_import = -1, \
372378
.bytes_warning = -1, \
373379
.inspect = -1, \

‎Include/internal/pycore_coreconfig.h‎

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,38 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE or Py_BUILD_CORE_BUILTIN defined"
99
#endif
1010

11-
/* --- _Py_wstrlist ----------------------------------------------- */
12-
13-
PyAPI_FUNC(void) _Py_wstrlist_clear(
14-
int len,
15-
wchar_t **list);
16-
PyAPI_FUNC(wchar_t**) _Py_wstrlist_copy(
17-
int len,
18-
wchar_t * const *list);
19-
PyAPI_FUNC(_PyInitError) _Py_wstrlist_append(
20-
int *len,
21-
wchar_t ***list,
22-
const wchar_t *str);
23-
PyAPI_FUNC(PyObject*) _Py_wstrlist_as_pylist(
24-
int len,
25-
wchar_t **list);
11+
12+
/* --- _PyWstrList ------------------------------------------------ */
13+
14+
#ifndef NDEBUG
15+
PyAPI_FUNC(int) _PyWstrList_CheckConsistency(const _PyWstrList *list);
16+
#endif
17+
PyAPI_FUNC(void) _PyWstrList_Clear(_PyWstrList *list);
18+
PyAPI_FUNC(int) _PyWstrList_Copy(_PyWstrList *list,
19+
const _PyWstrList *list2);
20+
PyAPI_FUNC(int) _PyWstrList_Append(_PyWstrList *list,
21+
const wchar_t *item);
22+
PyAPI_FUNC(PyObject*) _PyWstrList_AsList(const _PyWstrList *list);
23+
2624

2725
/* --- _PyArgv ---------------------------------------------------- */
2826

29-
PyAPI_FUNC(_PyInitError) _PyArgv_Decode(const _PyArgv *args,
30-
wchar_t*** argv_p);
27+
PyAPI_FUNC(_PyInitError) _PyArgv_AsWstrList(const _PyArgv *args,
28+
_PyWstrList *list);
29+
3130

3231
/* --- Py_GetArgcArgv() helpers ----------------------------------- */
3332

3433
PyAPI_FUNC(void) _Py_ClearArgcArgv(void);
3534

35+
3636
/* --- _PyPreConfig ----------------------------------------------- */
3737

3838
PyAPI_FUNC(int) _Py_str_to_int(
3939
const char *str,
4040
int *result);
4141
PyAPI_FUNC(const wchar_t*) _Py_get_xoption(
42-
int nxoption,
43-
wchar_t * const *xoptions,
42+
const _PyWstrList *xoptions,
4443
const wchar_t *name);
4544

4645
PyAPI_FUNC(void) _PyPreConfig_Clear(_PyPreConfig *config);

‎Include/internal/pycore_getopt.h‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
#endif
77

88
extern int _PyOS_opterr;
9-
extern int _PyOS_optind;
10-
extern wchar_t *_PyOS_optarg;
9+
extern Py_ssize_t _PyOS_optind;
10+
extern const wchar_t *_PyOS_optarg;
1111

1212
extern void _PyOS_ResetGetOpt(void);
1313

@@ -17,6 +17,6 @@ typedef struct {
1717
int val;
1818
} _PyOS_LongOption;
1919

20-
extern int _PyOS_GetOpt(int argc, wchar_t **argv, int *longindex);
20+
extern int _PyOS_GetOpt(Py_ssize_t argc, wchar_t **argv, int *longindex);
2121

2222
#endif /* !Py_INTERNAL_PYGETOPT_H */

‎Include/internal/pycore_pathconfig.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ PyAPI_FUNC(_PyInitError) _PyPathConfig_SetGlobal(
4444
PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate_impl(
4545
_PyPathConfig *config,
4646
const _PyCoreConfig *core_config);
47-
PyAPI_FUNC(PyObject*) _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv);
47+
PyAPI_FUNC(PyObject*) _PyPathConfig_ComputeArgv0(const _PyWstrList *argv);
4848
PyAPI_FUNC(int) _Py_FindEnvConfigValue(
4949
FILE *env_file,
5050
const wchar_t *key,

‎Modules/main.c‎

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,15 @@ mainconfig_add_xoption(PyObject *opts, const wchar_t *s)
8484
static PyObject*
8585
mainconfig_create_xoptions_dict(const _PyCoreConfig *config)
8686
{
87-
int nxoption = config->nxoption;
88-
wchar_t **xoptions = config->xoptions;
87+
Py_ssize_t nxoption = config->xoptions.length;
88+
wchar_t * const * xoptions = config->xoptions.items;
8989
PyObject *dict = PyDict_New();
9090
if (dict == NULL) {
9191
return NULL;
9292
}
9393

94-
for (int i=0; i < nxoption; i++) {
95-
wchar_t *option = xoptions[i];
94+
for (Py_ssize_t i=0; i < nxoption; i++) {
95+
const wchar_t *option = xoptions[i];
9696
if (mainconfig_add_xoption(dict, option) < 0) {
9797
Py_DECREF(dict);
9898
return NULL;
@@ -243,22 +243,18 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config,
243243
} \
244244
} \
245245
} while (0)
246-
#define COPY_WSTRLIST(ATTR, LEN, LIST) \
246+
#define COPY_WSTRLIST(ATTR, LIST) \
247247
do { \
248248
if (ATTR == NULL) { \
249-
ATTR = _Py_wstrlist_as_pylist(LEN, LIST); \
249+
ATTR = _PyWstrList_AsList(LIST); \
250250
if (ATTR == NULL) { \
251251
return _Py_INIT_NO_MEMORY(); \
252252
} \
253253
} \
254254
} while (0)
255255

256-
COPY_WSTRLIST(main_config->warnoptions,
257-
config->nwarnoption, config->warnoptions);
258-
if (config->argc >= 0) {
259-
COPY_WSTRLIST(main_config->argv,
260-
config->argc, config->argv);
261-
}
256+
COPY_WSTRLIST(main_config->warnoptions, &config->warnoptions);
257+
COPY_WSTRLIST(main_config->argv, &config->argv);
262258

263259
if (config->_install_importlib) {
264260
COPY_WSTR(executable);
@@ -268,7 +264,7 @@ _PyMainInterpreterConfig_Read(_PyMainInterpreterConfig *main_config,
268264
COPY_WSTR(base_exec_prefix);
269265

270266
COPY_WSTRLIST(main_config->module_search_path,
271-
config->nmodule_search_path, config->module_search_paths);
267+
&config->module_search_paths);
272268

273269
if (config->pycache_prefix != NULL) {
274270
COPY_WSTR(pycache_prefix);
@@ -784,8 +780,7 @@ pymain_run_python(PyInterpreterState *interp, int *exitcode)
784780
}
785781
}
786782
else if (!config->preconfig.isolated) {
787-
PyObject *path0 = _PyPathConfig_ComputeArgv0(config->argc,
788-
config->argv);
783+
PyObject *path0 = _PyPathConfig_ComputeArgv0(&config->argv);
789784
if (path0 == NULL) {
790785
err = _Py_INIT_NO_MEMORY();
791786
goto done;

‎Programs/_testembed.c‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -479,8 +479,8 @@ static int test_init_from_config(void)
479479
L"-c",
480480
L"pass",
481481
};
482-
config.argc = Py_ARRAY_LENGTH(argv);
483-
config.argv = argv;
482+
config.argv.length = Py_ARRAY_LENGTH(argv);
483+
config.argv.items = argv;
484484

485485
config.program = L"conf_program";
486486

@@ -489,15 +489,15 @@ static int test_init_from_config(void)
489489
L"core_xoption2=",
490490
L"core_xoption3",
491491
};
492-
config.nxoption = Py_ARRAY_LENGTH(xoptions);
493-
config.xoptions = xoptions;
492+
config.xoptions.length = Py_ARRAY_LENGTH(xoptions);
493+
config.xoptions.items = xoptions;
494494

495495
static wchar_t* warnoptions[2] = {
496496
L"default",
497497
L"error::ResourceWarning",
498498
};
499-
config.nwarnoption = Py_ARRAY_LENGTH(warnoptions);
500-
config.warnoptions = warnoptions;
499+
config.warnoptions.length = Py_ARRAY_LENGTH(warnoptions);
500+
config.warnoptions.items = warnoptions;
501501

502502
/* FIXME: test module_search_path_env */
503503
/* FIXME: test home */

0 commit comments

Comments
 (0)