Coverage Report

Created: 2026-10-17 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Python/getopt.c
Line
Count
Source
1
/*---------------------------------------------------------------------------*
2
 * <RCS keywords>
3
 *
4
 * C++ Library
5
 *
6
 * Copyright 1992-1994, David Gottner
7
 *
8
 *                    All Rights Reserved
9
 *
10
 * Permission to use, copy, modify, and distribute this software and its
11
 * documentation for any purpose and without fee is hereby granted,
12
 * provided that the above copyright notice, this permission notice and
13
 * the following disclaimer notice appear unmodified in all copies.
14
 *
15
 * I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL I
17
 * BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
18
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER
19
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
 *---------------------------------------------------------------------------*/
22
23
/* Modified to support --help and --version, as well as /? on Windows
24
 * by Georg Brandl. */
25
26
#include <Python.h>
27
#include <stdio.h>
28
#include <string.h>
29
#include <wchar.h>
30
#include "pycore_getopt.h"        // struct _PyOS_GetOpt
31
32
33
/* Python command line short and long options */
34
35
0
#define SHORT_OPTS L"bBc:dEhiIm:OPqRsStuvVW:xX:?"
36
37
typedef struct {
38
    const wchar_t *name;
39
    int has_arg;
40
    int val;
41
} _PyOS_LongOption;
42
43
static const _PyOS_LongOption longopts[] = {
44
    /* name, has_arg, val (used in switch in initconfig.c) */
45
    {L"check-hash-based-pycs", 1, 1},
46
    {L"help-all", 0, 2},
47
    {L"help-env", 0, 3},
48
    {L"help-xoptions", 0, 4},
49
    {NULL, 0, -1},                     /* sentinel */
50
};
51
52
53
void
54
_PyOS_GetOpt_Init(struct _PyOS_GetOpt *getopt,
55
                  Py_ssize_t argc, wchar_t * const *argv)
56
0
{
57
0
    getopt->error = 1;
58
0
    getopt->index = 1;
59
0
    getopt->arg = NULL;
60
0
    getopt->ptr = L"";
61
0
    getopt->argc = argc;
62
0
    getopt->argv = argv;
63
0
}
64
65
// Parse a command line option.
66
//
67
// Return a character for short option (ex: return 'h' for -h).
68
// Return a number for long options (see 'longopts' array).
69
// Return '_' on unknown option or missing argument.
70
// Return -1 when done.
71
//
72
// Return 'h' for --help and return 'V' for --version.
73
//
74
// If an option has an argument, set getopt->arg to the argument.
75
// If getopt->error is non-error, write error messages to stderr.
76
int
77
_PyOS_GetOpt(struct _PyOS_GetOpt *getopt)
78
0
{
79
    // Local copy of read-only members to omit "getopt->"
80
0
    const Py_ssize_t argc = getopt->argc;
81
0
    wchar_t * const *argv = getopt->argv;
82
0
    const int error = getopt->error;
83
84
0
    if (*getopt->ptr == '\0') {
85
0
        if (getopt->index >= argc) {
86
0
            return -1;
87
0
        }
88
89
0
        const wchar_t *arg = argv[getopt->index];
90
#ifdef MS_WINDOWS
91
        if (wcscmp(arg, L"/?") == 0) {
92
            ++getopt->index;
93
            return 'h';
94
        }
95
#endif
96
97
0
        if (arg[0] != L'-' || arg[1] == L'\0' /* lone dash */ ) {
98
0
            return -1;
99
0
        }
100
101
0
        if (wcscmp(arg, L"--") == 0) {
102
0
            ++getopt->index;
103
0
            return -1;
104
0
        }
105
0
        if (wcscmp(arg, L"--help") == 0) {
106
0
            ++getopt->index;
107
0
            return 'h';
108
0
        }
109
0
        if (wcscmp(arg, L"--version") == 0) {
110
0
            ++getopt->index;
111
0
            return 'V';
112
0
        }
113
114
0
        getopt->ptr = &argv[getopt->index++][1];
115
0
    }
116
117
0
    wchar_t option = *getopt->ptr++;
118
0
    if (option == L'\0') {
119
0
        return -1;
120
0
    }
121
122
0
    if (option == L'-') {
123
        // Parse long option.
124
0
        if (*getopt->ptr == L'\0') {
125
0
            if (error) {
126
0
                fprintf(stderr, "Expected long option\n");
127
0
            }
128
0
            return -1;
129
0
        }
130
0
        int longindex = 0;
131
0
        const _PyOS_LongOption *opt;
132
0
        for (opt = &longopts[longindex]; opt->name; opt = &longopts[++longindex]) {
133
0
            if (wcscmp(opt->name, getopt->ptr) == 0) {
134
0
                break;
135
0
            }
136
0
        }
137
138
0
        if (!opt->name) {
139
0
            if (error) {
140
0
                fprintf(stderr, "Unknown option: %ls\n", argv[getopt->index - 1]);
141
0
            }
142
0
            return '_';
143
0
        }
144
145
0
        getopt->ptr = L"";
146
0
        if (!opt->has_arg) {
147
0
            return opt->val;
148
0
        }
149
0
        if (getopt->index >= argc) {
150
0
            if (error) {
151
0
                fprintf(stderr, "Argument expected for the %ls options\n",
152
0
                        argv[getopt->index - 1]);
153
0
            }
154
0
            return '_';
155
0
        }
156
0
        getopt->arg = argv[getopt->index++];
157
0
        return opt->val;
158
0
    }
159
160
0
    wchar_t *ptr = wcschr(SHORT_OPTS, option);
161
0
    if (ptr == NULL) {
162
0
        if (error) {
163
0
            fprintf(stderr, "Unknown option: -%lc\n", option);
164
0
        }
165
0
        return '_';
166
0
    }
167
168
0
    if (*(ptr + 1) == L':') {
169
0
        if (*getopt->ptr != L'\0') {
170
0
            getopt->arg  = getopt->ptr;
171
0
            getopt->ptr = L"";
172
0
        }
173
0
        else {
174
0
            if (getopt->index >= argc) {
175
0
                if (error) {
176
0
                    fprintf(stderr,
177
0
                        "Argument expected for the -%lc option\n", option);
178
0
                }
179
0
                return '_';
180
0
            }
181
182
0
            getopt->arg = argv[getopt->index++];
183
0
        }
184
0
    }
185
186
0
    return option;
187
0
}