Skip to content

Commit c6689f6

Browse files
committed
Cleanup Python/getopt.c: add _PyOS_GetOpt structure
Replace global variables with a new _PyOS_GetOpt structure: * _PyOS_opterr: getopt->error * _PyOS_optind: getopt->index * _PyOS_optarg: getopt->arg Changes: * Rename _PyOS_ResetGetOpt() to _PyOS_GetOpt_Init(). Add argc and argv parameters. * Don't expose longindex in the structure, it's only used internally. * Move _PyOS_LongOption structure from the internal C API to getopt.c.
1 parent 89eee1f commit c6689f6

4 files changed

Lines changed: 98 additions & 88 deletions

File tree

‎Include/internal/pycore_getopt.h‎

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,21 @@
55
# error "this header requires Py_BUILD_CORE define"
66
#endif
77

8-
extern int _PyOS_opterr;
9-
extern Py_ssize_t _PyOS_optind;
10-
extern const wchar_t *_PyOS_optarg;
8+
struct _PyOS_GetOpt {
9+
int error; // generate error messages
10+
Py_ssize_t index; // index into argv array
11+
const wchar_t *arg; // optional argument
12+
const wchar_t *ptr;
13+
Py_ssize_t argc;
14+
wchar_t * const *argv;
15+
};
1116

12-
extern void _PyOS_ResetGetOpt(void);
17+
extern void _PyOS_GetOpt_Init(
18+
struct _PyOS_GetOpt *getopt,
19+
Py_ssize_t argc,
20+
wchar_t * const *argv);
1321

14-
typedef struct {
15-
const wchar_t *name;
16-
int has_arg;
17-
int val;
18-
} _PyOS_LongOption;
19-
20-
extern int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex);
22+
extern int _PyOS_GetOpt(
23+
struct _PyOS_GetOpt *getopt);
2124

2225
#endif /* !Py_INTERNAL_PYGETOPT_H */

‎Python/getopt.c‎

Lines changed: 62 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,19 @@
2727
#include <stdio.h>
2828
#include <string.h>
2929
#include <wchar.h>
30-
#include "pycore_getopt.h"
30+
#include "pycore_getopt.h" // struct _PyOS_GetOpt
3131

32-
int _PyOS_opterr = 1; /* generate error messages */
33-
Py_ssize_t _PyOS_optind = 1; /* index into argv array */
34-
const wchar_t *_PyOS_optarg = NULL; /* optional argument */
35-
36-
static const wchar_t *opt_ptr = L"";
3732

3833
/* Python command line short and long options */
3934

4035
#define SHORT_OPTS L"bBc:dEhiIm:OPqRsStuvVW:xX:?"
4136

37+
typedef struct {
38+
const wchar_t *name;
39+
int has_arg;
40+
int val;
41+
} _PyOS_LongOption;
42+
4243
static const _PyOS_LongOption longopts[] = {
4344
/* name, has_arg, val (used in switch in initconfig.c) */
4445
{L"check-hash-based-pycs", 1, 1},
@@ -49,113 +50,119 @@ static const _PyOS_LongOption longopts[] = {
4950
};
5051

5152

52-
void _PyOS_ResetGetOpt(void)
53+
void
54+
_PyOS_GetOpt_Init(struct _PyOS_GetOpt *getopt,
55+
Py_ssize_t argc, wchar_t * const *argv)
5356
{
54-
_PyOS_opterr = 1;
55-
_PyOS_optind = 1;
56-
_PyOS_optarg = NULL;
57-
opt_ptr = L"";
57+
getopt->error = 1;
58+
getopt->index = 1;
59+
getopt->arg = NULL;
60+
getopt->ptr = L"";
61+
getopt->argc = argc;
62+
getopt->argv = argv;
5863
}
5964

60-
int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
65+
int
66+
_PyOS_GetOpt(struct _PyOS_GetOpt *getopt)
6167
{
62-
wchar_t *ptr;
63-
wchar_t option;
64-
65-
if (*opt_ptr == '\0') {
68+
if (*getopt->ptr == '\0') {
69+
if (getopt->index >= getopt->argc) {
70+
return -1;
71+
}
6672

67-
if (_PyOS_optind >= argc)
73+
const wchar_t *arg = getopt->argv[getopt->index];
74+
if (arg[0] != L'-' || arg[1] == L'\0' /* lone dash */ ) {
6875
return -1;
76+
}
77+
6978
#ifdef MS_WINDOWS
70-
else if (wcscmp(argv[_PyOS_optind], L"/?") == 0) {
71-
++_PyOS_optind;
79+
if (wcscmp(arg, L"/?") == 0) {
80+
++getopt->index;
7281
return 'h';
7382
}
7483
#endif
75-
76-
else if (argv[_PyOS_optind][0] != L'-' ||
77-
argv[_PyOS_optind][1] == L'\0' /* lone dash */ )
78-
return -1;
79-
80-
else if (wcscmp(argv[_PyOS_optind], L"--") == 0) {
81-
++_PyOS_optind;
84+
if (wcscmp(arg, L"--") == 0) {
85+
++getopt->index;
8286
return -1;
8387
}
84-
85-
else if (wcscmp(argv[_PyOS_optind], L"--help") == 0) {
86-
++_PyOS_optind;
88+
if (wcscmp(arg, L"--help") == 0) {
89+
++getopt->index;
8790
return 'h';
8891
}
89-
90-
else if (wcscmp(argv[_PyOS_optind], L"--version") == 0) {
91-
++_PyOS_optind;
92+
if (wcscmp(arg, L"--version") == 0) {
93+
++getopt->index;
9294
return 'V';
9395
}
9496

95-
opt_ptr = &argv[_PyOS_optind++][1];
97+
getopt->ptr = &getopt->argv[getopt->index++][1];
9698
}
9799

98-
if ((option = *opt_ptr++) == L'\0')
100+
wchar_t option = *getopt->ptr++;
101+
if (option == L'\0') {
99102
return -1;
103+
}
100104

101105
if (option == L'-') {
102106
// Parse long option.
103-
if (*opt_ptr == L'\0') {
104-
if (_PyOS_opterr) {
107+
if (*getopt->ptr == L'\0') {
108+
if (getopt->error) {
105109
fprintf(stderr, "Expected long option\n");
106110
}
107111
return -1;
108112
}
109-
*longindex = 0;
113+
int longindex = 0;
110114
const _PyOS_LongOption *opt;
111-
for (opt = &longopts[*longindex]; opt->name; opt = &longopts[++(*longindex)]) {
112-
if (!wcscmp(opt->name, opt_ptr))
115+
for (opt = &longopts[longindex]; opt->name; opt = &longopts[++longindex]) {
116+
if (wcscmp(opt->name, getopt->ptr) == 0) {
113117
break;
118+
}
114119
}
120+
115121
if (!opt->name) {
116-
if (_PyOS_opterr) {
117-
fprintf(stderr, "Unknown option: %ls\n", argv[_PyOS_optind - 1]);
122+
if (getopt->error) {
123+
fprintf(stderr, "Unknown option: %ls\n", getopt->argv[getopt->index - 1]);
118124
}
119125
return '_';
120126
}
121-
opt_ptr = L"";
127+
128+
getopt->ptr = L"";
122129
if (!opt->has_arg) {
123130
return opt->val;
124131
}
125-
if (_PyOS_optind >= argc) {
126-
if (_PyOS_opterr) {
132+
if (getopt->index >= getopt->argc) {
133+
if (getopt->error) {
127134
fprintf(stderr, "Argument expected for the %ls options\n",
128-
argv[_PyOS_optind - 1]);
135+
getopt->argv[getopt->index - 1]);
129136
}
130137
return '_';
131138
}
132-
_PyOS_optarg = argv[_PyOS_optind++];
139+
getopt->arg = getopt->argv[getopt->index++];
133140
return opt->val;
134141
}
135142

136-
if ((ptr = wcschr(SHORT_OPTS, option)) == NULL) {
137-
if (_PyOS_opterr) {
143+
wchar_t *ptr = wcschr(SHORT_OPTS, option);
144+
if (ptr == NULL) {
145+
if (getopt->error) {
138146
fprintf(stderr, "Unknown option: -%c\n", (char)option);
139147
}
140148
return '_';
141149
}
142150

143151
if (*(ptr + 1) == L':') {
144-
if (*opt_ptr != L'\0') {
145-
_PyOS_optarg = opt_ptr;
146-
opt_ptr = L"";
152+
if (*getopt->ptr != L'\0') {
153+
getopt->arg = getopt->ptr;
154+
getopt->ptr = L"";
147155
}
148-
149156
else {
150-
if (_PyOS_optind >= argc) {
151-
if (_PyOS_opterr) {
157+
if (getopt->index >= getopt->argc) {
158+
if (getopt->error) {
152159
fprintf(stderr,
153160
"Argument expected for the -%c option\n", (char)option);
154161
}
155162
return '_';
156163
}
157164

158-
_PyOS_optarg = argv[_PyOS_optind++];
165+
getopt->arg = getopt->argv[getopt->index++];
159166
}
160167
}
161168

‎Python/initconfig.c‎

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,10 +3009,10 @@ config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions,
30093009
const PyWideStringList *argv = &config->argv;
30103010
int print_version = 0;
30113011

3012-
_PyOS_ResetGetOpt();
3012+
struct _PyOS_GetOpt getopt;
3013+
_PyOS_GetOpt_Init(&getopt, argv->length, argv->items);
30133014
do {
3014-
int longindex = -1;
3015-
int c = _PyOS_GetOpt(argv->length, argv->items, &longindex);
3015+
int c = _PyOS_GetOpt(&getopt);
30163016
if (c == EOF) {
30173017
break;
30183018
}
@@ -3022,12 +3022,12 @@ config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions,
30223022
/* -c is the last option; following arguments
30233023
that look like options are left for the
30243024
command to interpret. */
3025-
size_t len = wcslen(_PyOS_optarg) + 1 + 1;
3025+
size_t len = wcslen(getopt.arg) + 1 + 1;
30263026
wchar_t *command = PyMem_RawMalloc(sizeof(wchar_t) * len);
30273027
if (command == NULL) {
30283028
return _PyStatus_NO_MEMORY();
30293029
}
3030-
memcpy(command, _PyOS_optarg, (len - 2) * sizeof(wchar_t));
3030+
memcpy(command, getopt.arg, (len - 2) * sizeof(wchar_t));
30313031
command[len - 2] = '\n';
30323032
command[len - 1] = 0;
30333033
config->run_command = command;
@@ -3040,7 +3040,7 @@ config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions,
30403040
that look like options are left for the
30413041
module to interpret. */
30423042
if (config->run_module == NULL) {
3043-
config->run_module = _PyMem_RawWcsdup(_PyOS_optarg);
3043+
config->run_module = _PyMem_RawWcsdup(getopt.arg);
30443044
if (config->run_module == NULL) {
30453045
return _PyStatus_NO_MEMORY();
30463046
}
@@ -3052,12 +3052,12 @@ config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions,
30523052
// Integers represent long options, see Python/getopt.c
30533053
case 1:
30543054
// check-hash-based-pycs
3055-
if (wcscmp(_PyOS_optarg, L"always") == 0
3056-
|| wcscmp(_PyOS_optarg, L"never") == 0
3057-
|| wcscmp(_PyOS_optarg, L"default") == 0)
3055+
if (wcscmp(getopt.arg, L"always") == 0
3056+
|| wcscmp(getopt.arg, L"never") == 0
3057+
|| wcscmp(getopt.arg, L"default") == 0)
30583058
{
30593059
status = PyConfig_SetString(config, &config->check_hash_pycs_mode,
3060-
_PyOS_optarg);
3060+
getopt.arg);
30613061
if (_PyStatus_EXCEPTION(status)) {
30623062
return status;
30633063
}
@@ -3146,7 +3146,7 @@ config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions,
31463146
break;
31473147

31483148
case 'W':
3149-
status = PyWideStringList_Append(warnoptions, _PyOS_optarg);
3149+
status = PyWideStringList_Append(warnoptions, getopt.arg);
31503150
if (_PyStatus_EXCEPTION(status)) {
31513151
return status;
31523152
}
@@ -3177,22 +3177,22 @@ config_parse_cmdline(PyConfig *config, PyWideStringList *warnoptions,
31773177
}
31783178

31793179
if (config->run_command == NULL && config->run_module == NULL
3180-
&& _PyOS_optind < argv->length
3181-
&& wcscmp(argv->items[_PyOS_optind], L"-") != 0
3180+
&& getopt.index < argv->length
3181+
&& wcscmp(argv->items[getopt.index], L"-") != 0
31823182
&& config->run_filename == NULL)
31833183
{
3184-
config->run_filename = _PyMem_RawWcsdup(argv->items[_PyOS_optind]);
3184+
config->run_filename = _PyMem_RawWcsdup(argv->items[getopt.index]);
31853185
if (config->run_filename == NULL) {
31863186
return _PyStatus_NO_MEMORY();
31873187
}
31883188
}
31893189

31903190
if (config->run_command != NULL || config->run_module != NULL) {
3191-
/* Backup _PyOS_optind */
3192-
_PyOS_optind--;
3191+
/* Backup getopt.index */
3192+
getopt.index--;
31933193
}
31943194

3195-
*opt_index = _PyOS_optind;
3195+
*opt_index = getopt.index;
31963196

31973197
return _PyStatus_OK();
31983198

‎Python/preconfig.c‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,13 @@ precmdline_parse_cmdline(_PyPreCmdline *cmdline)
187187
{
188188
const PyWideStringList *argv = &cmdline->argv;
189189

190-
_PyOS_ResetGetOpt();
190+
struct _PyOS_GetOpt getopt;
191+
_PyOS_GetOpt_Init(&getopt, argv->length, argv->items);
191192
/* Don't log parsing errors into stderr here: PyConfig_Read()
192193
is responsible for that */
193-
_PyOS_opterr = 0;
194+
getopt.error = 0;
194195
do {
195-
int longindex = -1;
196-
int c = _PyOS_GetOpt(argv->length, argv->items, &longindex);
196+
int c = _PyOS_GetOpt(&getopt);
197197

198198
if (c == EOF || c == 'c' || c == 'm') {
199199
break;
@@ -211,7 +211,7 @@ precmdline_parse_cmdline(_PyPreCmdline *cmdline)
211211
case 'X':
212212
{
213213
PyStatus status = PyWideStringList_Append(&cmdline->xoptions,
214-
_PyOS_optarg);
214+
getopt.arg);
215215
if (_PyStatus_EXCEPTION(status)) {
216216
return status;
217217
}

0 commit comments

Comments
 (0)