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"
31 
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35 
36 int _PyOS_opterr = 1;                 /* generate error messages */
37 Py_ssize_t _PyOS_optind = 1;          /* index into argv array   */
38 const wchar_t *_PyOS_optarg = NULL;   /* optional argument       */
39 
40 static const wchar_t *opt_ptr = L"";
41 
42 /* Python command line short and long options */
43 
44 #define SHORT_OPTS L"bBc:dEhiIJm:OPqRsStuvVW:xX:?"
45 
46 static const _PyOS_LongOption longopts[] = {
47     /* name, has_arg, val (used in switch in initconfig.c) */
48     {L"check-hash-based-pycs", 1, 0},
49     {L"help-all", 0, 1},
50     {L"help-env", 0, 2},
51     {L"help-xoptions", 0, 3},
52     {NULL, 0, -1},                     /* sentinel */
53 };
54 
55 
_PyOS_ResetGetOpt(void)56 void _PyOS_ResetGetOpt(void)
57 {
58     _PyOS_opterr = 1;
59     _PyOS_optind = 1;
60     _PyOS_optarg = NULL;
61     opt_ptr = L"";
62 }
63 
_PyOS_GetOpt(Py_ssize_t argc,wchar_t * const * argv,int * longindex)64 int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
65 {
66     wchar_t *ptr;
67     wchar_t option;
68 
69     if (*opt_ptr == '\0') {
70 
71         if (_PyOS_optind >= argc)
72             return -1;
73 #ifdef MS_WINDOWS
74         else if (wcscmp(argv[_PyOS_optind], L"/?") == 0) {
75             ++_PyOS_optind;
76             return 'h';
77         }
78 #endif
79 
80         else if (argv[_PyOS_optind][0] != L'-' ||
81                  argv[_PyOS_optind][1] == L'\0' /* lone dash */ )
82             return -1;
83 
84         else if (wcscmp(argv[_PyOS_optind], L"--") == 0) {
85             ++_PyOS_optind;
86             return -1;
87         }
88 
89         else if (wcscmp(argv[_PyOS_optind], L"--help") == 0) {
90             ++_PyOS_optind;
91             return 'h';
92         }
93 
94         else if (wcscmp(argv[_PyOS_optind], L"--version") == 0) {
95             ++_PyOS_optind;
96             return 'V';
97         }
98 
99         opt_ptr = &argv[_PyOS_optind++][1];
100     }
101 
102     if ((option = *opt_ptr++) == L'\0')
103         return -1;
104 
105     if (option == L'-') {
106         // Parse long option.
107         if (*opt_ptr == L'\0') {
108             if (_PyOS_opterr) {
109                 fprintf(stderr, "expected long option\n");
110             }
111             return -1;
112         }
113         *longindex = 0;
114         const _PyOS_LongOption *opt;
115         for (opt = &longopts[*longindex]; opt->name; opt = &longopts[++(*longindex)]) {
116             if (!wcscmp(opt->name, opt_ptr))
117                 break;
118         }
119         if (!opt->name) {
120             if (_PyOS_opterr) {
121                 fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]);
122             }
123             return '_';
124         }
125         opt_ptr = L"";
126         if (!opt->has_arg) {
127             return opt->val;
128         }
129         if (_PyOS_optind >= argc) {
130             if (_PyOS_opterr) {
131                 fprintf(stderr, "Argument expected for the %ls options\n",
132                         argv[_PyOS_optind - 1]);
133             }
134             return '_';
135         }
136         _PyOS_optarg = argv[_PyOS_optind++];
137         return opt->val;
138     }
139 
140     if (option == 'J') {
141         if (_PyOS_opterr) {
142             fprintf(stderr, "-J is reserved for Jython\n");
143         }
144         return '_';
145     }
146 
147     if ((ptr = wcschr(SHORT_OPTS, option)) == NULL) {
148         if (_PyOS_opterr) {
149             fprintf(stderr, "Unknown option: -%c\n", (char)option);
150         }
151         return '_';
152     }
153 
154     if (*(ptr + 1) == L':') {
155         if (*opt_ptr != L'\0') {
156             _PyOS_optarg  = opt_ptr;
157             opt_ptr = L"";
158         }
159 
160         else {
161             if (_PyOS_optind >= argc) {
162                 if (_PyOS_opterr) {
163                     fprintf(stderr,
164                         "Argument expected for the -%c option\n", (char)option);
165                 }
166                 return '_';
167             }
168 
169             _PyOS_optarg = argv[_PyOS_optind++];
170         }
171     }
172 
173     return option;
174 }
175 
176 #ifdef __cplusplus
177 }
178 #endif
179 
180