1a1ee3836SEvan Lloyd /*
2*cb5c08b6SSami Mujawar * Copyright (c) 2017 - 2020, Arm Limited and Contributors. All rights reserved.
3a1ee3836SEvan Lloyd *
4a1ee3836SEvan Lloyd * SPDX-License-Identifier: BSD-3-Clause
5a1ee3836SEvan Lloyd */
6a1ee3836SEvan Lloyd
7a1ee3836SEvan Lloyd #include <assert.h>
8a1ee3836SEvan Lloyd
9a1ee3836SEvan Lloyd #include "win_posix.h"
10a1ee3836SEvan Lloyd
11a1ee3836SEvan Lloyd /*
12a1ee3836SEvan Lloyd * This variable is set by getopt to the index of the next element of the
13a1ee3836SEvan Lloyd * argv array to be processed. Once getopt has found all of the option
14a1ee3836SEvan Lloyd * arguments, you can use this variable to determine where the remaining
15a1ee3836SEvan Lloyd * non-option arguments begin. The initial value of this variable is 1.
16a1ee3836SEvan Lloyd */
17a1ee3836SEvan Lloyd int optind = 1;
18a1ee3836SEvan Lloyd
19a1ee3836SEvan Lloyd /*
20a1ee3836SEvan Lloyd * If the value of this variable is nonzero, then getopt prints an error
21a1ee3836SEvan Lloyd * message to the standard error stream if it encounters an unknown option
22a1ee3836SEvan Lloyd * default character or an option with a missing required argument.
23a1ee3836SEvan Lloyd * If you set this variable to zero, getopt does not print any messages,
24a1ee3836SEvan Lloyd * but it still returns the character ? to indicate an error.
25a1ee3836SEvan Lloyd */
26a1ee3836SEvan Lloyd const int opterr; /* = 0; */
27a1ee3836SEvan Lloyd /* const because we do not implement error printing.*/
28a1ee3836SEvan Lloyd /* Not initialised to conform with the coding standard. */
29a1ee3836SEvan Lloyd
30a1ee3836SEvan Lloyd /*
31a1ee3836SEvan Lloyd * When getopt encounters an unknown option character or an option with a
32a1ee3836SEvan Lloyd * missing required argument, it stores that option character in this
33a1ee3836SEvan Lloyd * variable.
34a1ee3836SEvan Lloyd */
35a1ee3836SEvan Lloyd int optopt; /* = 0; */
36a1ee3836SEvan Lloyd
37a1ee3836SEvan Lloyd /*
38a1ee3836SEvan Lloyd * This variable is set by getopt to point at the value of the option
39a1ee3836SEvan Lloyd * argument, for those options that accept arguments.
40a1ee3836SEvan Lloyd */
41a1ee3836SEvan Lloyd char *optarg; /* = 0; */
42a1ee3836SEvan Lloyd
43a1ee3836SEvan Lloyd enum return_flags {
44a1ee3836SEvan Lloyd RET_ERROR = -1,
45a1ee3836SEvan Lloyd RET_END_OPT_LIST = -1,
46a1ee3836SEvan Lloyd RET_NO_PARAM = '?',
47a1ee3836SEvan Lloyd RET_NO_PARAM2 = ':',
48a1ee3836SEvan Lloyd RET_UNKNOWN_OPT = '?'
49a1ee3836SEvan Lloyd };
50a1ee3836SEvan Lloyd
51a1ee3836SEvan Lloyd /*
52a1ee3836SEvan Lloyd * Common initialisation on entry.
53a1ee3836SEvan Lloyd */
54a1ee3836SEvan Lloyd static
getopt_init(void)55a1ee3836SEvan Lloyd void getopt_init(void)
56a1ee3836SEvan Lloyd {
57a1ee3836SEvan Lloyd optarg = (char *)0;
58a1ee3836SEvan Lloyd optopt = 0;
59a1ee3836SEvan Lloyd /* optind may be zero with some POSIX uses.
60a1ee3836SEvan Lloyd * For our purposes we just change it to 1.
61a1ee3836SEvan Lloyd */
62a1ee3836SEvan Lloyd if (optind == 0)
63a1ee3836SEvan Lloyd optind = 1;
64a1ee3836SEvan Lloyd }
65a1ee3836SEvan Lloyd
66a1ee3836SEvan Lloyd /*
67a1ee3836SEvan Lloyd * Common handling for a single letter option.
68a1ee3836SEvan Lloyd */
69a1ee3836SEvan Lloyd static
getopt_1char(int argc,char * const argv[],const char * const opstring,const int optchar)70a1ee3836SEvan Lloyd int getopt_1char(int argc,
71a1ee3836SEvan Lloyd char *const argv[],
72a1ee3836SEvan Lloyd const char *const opstring,
73a1ee3836SEvan Lloyd const int optchar)
74a1ee3836SEvan Lloyd {
75a1ee3836SEvan Lloyd size_t nlen = (opstring == 0) ? 0 : strlen(opstring);
76a1ee3836SEvan Lloyd size_t loptn;
77a1ee3836SEvan Lloyd
78a1ee3836SEvan Lloyd for (loptn = 0; loptn < nlen; loptn++) {
79a1ee3836SEvan Lloyd if (optchar == opstring[loptn]) {
80a1ee3836SEvan Lloyd if (opstring[loptn + 1] == ':') {
81a1ee3836SEvan Lloyd /* Option has argument */
82a1ee3836SEvan Lloyd if (optind < argc) {
83a1ee3836SEvan Lloyd /* Found argument. */
84a1ee3836SEvan Lloyd assert(argv != 0);
85a1ee3836SEvan Lloyd optind++;
86a1ee3836SEvan Lloyd optarg = argv[optind++];
87a1ee3836SEvan Lloyd return optchar;
88a1ee3836SEvan Lloyd }
89a1ee3836SEvan Lloyd /* Missing argument. */
90a1ee3836SEvan Lloyd if (opstring[loptn + 2] == ':') {
91a1ee3836SEvan Lloyd /* OK if optional "x::". */
92a1ee3836SEvan Lloyd optind++;
93a1ee3836SEvan Lloyd return optchar;
94a1ee3836SEvan Lloyd }
95a1ee3836SEvan Lloyd /* Actual missing value. */
96a1ee3836SEvan Lloyd optopt = optchar;
97a1ee3836SEvan Lloyd return ((opstring[0] == ':')
98a1ee3836SEvan Lloyd ? RET_NO_PARAM2
99a1ee3836SEvan Lloyd : RET_NO_PARAM);
100a1ee3836SEvan Lloyd }
101a1ee3836SEvan Lloyd /* No argument, just return option char */
102a1ee3836SEvan Lloyd optind++;
103a1ee3836SEvan Lloyd return optchar;
104a1ee3836SEvan Lloyd }
105a1ee3836SEvan Lloyd }
106a1ee3836SEvan Lloyd /*
107a1ee3836SEvan Lloyd * If getopt finds an option character in argv that was not included in
108a1ee3836SEvan Lloyd * options, ... it returns '?' and sets the external variable optopt to
109a1ee3836SEvan Lloyd * the actual option character.
110a1ee3836SEvan Lloyd */
111a1ee3836SEvan Lloyd optopt = optchar;
112a1ee3836SEvan Lloyd return RET_UNKNOWN_OPT;
113a1ee3836SEvan Lloyd }
114a1ee3836SEvan Lloyd
getopt(int argc,char * argv[],char * opstring)115a1ee3836SEvan Lloyd int getopt(int argc,
116a1ee3836SEvan Lloyd char *argv[],
117a1ee3836SEvan Lloyd char *opstring)
118a1ee3836SEvan Lloyd {
119a1ee3836SEvan Lloyd int result = RET_END_OPT_LIST;
120a1ee3836SEvan Lloyd size_t argn = 0;
121a1ee3836SEvan Lloyd size_t nlen = strlen(opstring);
122a1ee3836SEvan Lloyd
123a1ee3836SEvan Lloyd getopt_init();
124a1ee3836SEvan Lloyd /* If we have an argument left to play with */
125a1ee3836SEvan Lloyd if ((argc > optind) && (argv != 0)) {
126a1ee3836SEvan Lloyd const char *arg = (const char *)argv[optind];
127a1ee3836SEvan Lloyd
128a1ee3836SEvan Lloyd if ((arg != 0) && (arg[0] == '-'))
129a1ee3836SEvan Lloyd result = getopt_1char(argc, argv, opstring, arg[1]);
130a1ee3836SEvan Lloyd }
131a1ee3836SEvan Lloyd
132a1ee3836SEvan Lloyd return result;
133a1ee3836SEvan Lloyd }
134a1ee3836SEvan Lloyd
135a1ee3836SEvan Lloyd /*
136a1ee3836SEvan Lloyd * Match an argument value against an option name.
137a1ee3836SEvan Lloyd * Note that we only match over the shorter length of the pair, to allow
138a1ee3836SEvan Lloyd * for abbreviation or say --match=value
139a1ee3836SEvan Lloyd * Long option names may be abbreviated if the abbreviation is unique or an
140*cb5c08b6SSami Mujawar * exact match for some defined option. This function does not check that the
141*cb5c08b6SSami Mujawar * abbreviations are unique and should be handled by the caller.
142a1ee3836SEvan Lloyd * A long option may take a parameter, of the form --opt=param or --opt param.
143a1ee3836SEvan Lloyd */
144a1ee3836SEvan Lloyd static
optmatch(const char * argval,const char * optname)145a1ee3836SEvan Lloyd int optmatch(const char *argval, const char *optname)
146a1ee3836SEvan Lloyd {
147a1ee3836SEvan Lloyd int result = 0;
148a1ee3836SEvan Lloyd
149a1ee3836SEvan Lloyd while ((result == 0) && (*optname != 0) && (*argval != 0))
150a1ee3836SEvan Lloyd result = (*argval++) - (*optname++);
151a1ee3836SEvan Lloyd return result;
152a1ee3836SEvan Lloyd }
153a1ee3836SEvan Lloyd
154a1ee3836SEvan Lloyd /* Handling for a single long option. */
155a1ee3836SEvan Lloyd static
getopt_1long(const int argc,char * const argv[],const struct option * const longopts,const char * const optname,int * const indexptr)156a1ee3836SEvan Lloyd int getopt_1long(const int argc,
157a1ee3836SEvan Lloyd char *const argv[],
158a1ee3836SEvan Lloyd const struct option *const longopts,
159a1ee3836SEvan Lloyd const char *const optname,
160a1ee3836SEvan Lloyd int *const indexptr)
161a1ee3836SEvan Lloyd {
162a1ee3836SEvan Lloyd int result = RET_UNKNOWN_OPT;
163a1ee3836SEvan Lloyd size_t loptn = 0;
164*cb5c08b6SSami Mujawar bool match_found = false;
165a1ee3836SEvan Lloyd
166*cb5c08b6SSami Mujawar /*
167*cb5c08b6SSami Mujawar * Long option names may be abbreviated if the abbreviation
168*cb5c08b6SSami Mujawar * is unique or an exact match for some defined option.
169*cb5c08b6SSami Mujawar * To handle this:
170*cb5c08b6SSami Mujawar * - First search for an exact match.
171*cb5c08b6SSami Mujawar * - If exact match was not found search for a abbreviated match.
172*cb5c08b6SSami Mujawar * By doing this an incorrect option selection can be avoided.
173*cb5c08b6SSami Mujawar */
174*cb5c08b6SSami Mujawar
175*cb5c08b6SSami Mujawar /* 1. Search for an exact match. */
176*cb5c08b6SSami Mujawar while (longopts[loptn].name != NULL) {
177*cb5c08b6SSami Mujawar if (strcmp(optname, longopts[loptn].name) == 0) {
178*cb5c08b6SSami Mujawar match_found = true;
179*cb5c08b6SSami Mujawar break;
180*cb5c08b6SSami Mujawar }
181*cb5c08b6SSami Mujawar ++loptn;
182*cb5c08b6SSami Mujawar }
183*cb5c08b6SSami Mujawar
184*cb5c08b6SSami Mujawar /* 2. If exact match was not found search for a abbreviated match. */
185*cb5c08b6SSami Mujawar if (!match_found) {
186*cb5c08b6SSami Mujawar loptn = 0;
187*cb5c08b6SSami Mujawar while (longopts[loptn].name != NULL) {
188a1ee3836SEvan Lloyd if (optmatch(optname, longopts[loptn].name) == 0) {
189*cb5c08b6SSami Mujawar match_found = true;
190*cb5c08b6SSami Mujawar break;
191*cb5c08b6SSami Mujawar }
192*cb5c08b6SSami Mujawar ++loptn;
193*cb5c08b6SSami Mujawar }
194*cb5c08b6SSami Mujawar }
195*cb5c08b6SSami Mujawar
196*cb5c08b6SSami Mujawar if (match_found) {
197a1ee3836SEvan Lloyd /* We found a match. */
198a1ee3836SEvan Lloyd result = longopts[loptn].val;
199*cb5c08b6SSami Mujawar if (indexptr != 0) {
200a1ee3836SEvan Lloyd *indexptr = loptn;
201*cb5c08b6SSami Mujawar }
202a1ee3836SEvan Lloyd switch (longopts[loptn].has_arg) {
203a1ee3836SEvan Lloyd case required_argument:
204a1ee3836SEvan Lloyd if ((optind + 1) >= argc) {
205a1ee3836SEvan Lloyd /* Missing argument. */
206a1ee3836SEvan Lloyd optopt = result;
207a1ee3836SEvan Lloyd return RET_NO_PARAM;
208a1ee3836SEvan Lloyd }
209a1ee3836SEvan Lloyd /* Fallthrough to get option value. */
210a1ee3836SEvan Lloyd
211a1ee3836SEvan Lloyd case optional_argument:
212a1ee3836SEvan Lloyd if ((argc - optind) > 0) {
213a1ee3836SEvan Lloyd /* Found argument. */
214a1ee3836SEvan Lloyd optarg = argv[++optind];
215a1ee3836SEvan Lloyd }
216a1ee3836SEvan Lloyd /* Fallthrough to handle flag. */
217a1ee3836SEvan Lloyd
218a1ee3836SEvan Lloyd case no_argument:
219a1ee3836SEvan Lloyd optind++;
220a1ee3836SEvan Lloyd if (longopts[loptn].flag != 0) {
221a1ee3836SEvan Lloyd *longopts[loptn].flag = result;
222a1ee3836SEvan Lloyd result = 0;
223a1ee3836SEvan Lloyd }
224a1ee3836SEvan Lloyd break;
225a1ee3836SEvan Lloyd
226a1ee3836SEvan Lloyd }
227a1ee3836SEvan Lloyd return result;
228a1ee3836SEvan Lloyd }
229*cb5c08b6SSami Mujawar
230a1ee3836SEvan Lloyd /*
231a1ee3836SEvan Lloyd * If getopt finds an option character in argv that was not included
232a1ee3836SEvan Lloyd * in options, ... it returns '?' and sets the external variable
233a1ee3836SEvan Lloyd * optopt to the actual option character.
234a1ee3836SEvan Lloyd */
235a1ee3836SEvan Lloyd return RET_UNKNOWN_OPT;
236a1ee3836SEvan Lloyd }
237a1ee3836SEvan Lloyd
238a1ee3836SEvan Lloyd /*
239a1ee3836SEvan Lloyd * getopt_long gets the next option argument from the argument list
240a1ee3836SEvan Lloyd * specified by the argv and argc arguments. Options may be either short
241a1ee3836SEvan Lloyd * (single letter) as for getopt, or longer names (preceded by --).
242a1ee3836SEvan Lloyd */
getopt_long(int argc,char * argv[],const char * shortopts,const struct option * longopts,int * indexptr)243a1ee3836SEvan Lloyd int getopt_long(int argc,
244a1ee3836SEvan Lloyd char *argv[],
245a1ee3836SEvan Lloyd const char *shortopts,
246a1ee3836SEvan Lloyd const struct option *longopts,
247a1ee3836SEvan Lloyd int *indexptr)
248a1ee3836SEvan Lloyd {
249a1ee3836SEvan Lloyd int result = RET_END_OPT_LIST;
250a1ee3836SEvan Lloyd
251a1ee3836SEvan Lloyd getopt_init();
252a1ee3836SEvan Lloyd /* If we have an argument left to play with */
253a1ee3836SEvan Lloyd if ((argc > optind) && (argv != 0)) {
254a1ee3836SEvan Lloyd const char *arg = argv[optind];
255a1ee3836SEvan Lloyd
256a1ee3836SEvan Lloyd if ((arg != 0) && (arg[0] == '-')) {
257a1ee3836SEvan Lloyd if (arg[1] == '-') {
258a1ee3836SEvan Lloyd /* Looks like a long option. */
259a1ee3836SEvan Lloyd result = getopt_1long(argc,
260a1ee3836SEvan Lloyd argv,
261a1ee3836SEvan Lloyd longopts,
262a1ee3836SEvan Lloyd &arg[2],
263a1ee3836SEvan Lloyd indexptr);
264a1ee3836SEvan Lloyd } else {
265a1ee3836SEvan Lloyd result = getopt_1char(argc,
266a1ee3836SEvan Lloyd argv,
267a1ee3836SEvan Lloyd shortopts,
268a1ee3836SEvan Lloyd arg[1]);
269a1ee3836SEvan Lloyd }
270a1ee3836SEvan Lloyd }
271a1ee3836SEvan Lloyd }
272a1ee3836SEvan Lloyd return result;
273a1ee3836SEvan Lloyd }
274a1ee3836SEvan Lloyd
275a1ee3836SEvan Lloyd /*
276a1ee3836SEvan Lloyd * getopt_long_only gets the next option argument from the argument list
277a1ee3836SEvan Lloyd * specified by the argv and argc arguments. Options may be either short
278a1ee3836SEvan Lloyd * or long as for getopt_long, but the long names may have a single '-'
279a1ee3836SEvan Lloyd * prefix too.
280a1ee3836SEvan Lloyd */
getopt_long_only(int argc,char * argv[],const char * shortopts,const struct option * longopts,int * indexptr)281a1ee3836SEvan Lloyd int getopt_long_only(int argc,
282a1ee3836SEvan Lloyd char *argv[],
283a1ee3836SEvan Lloyd const char *shortopts,
284a1ee3836SEvan Lloyd const struct option *longopts,
285a1ee3836SEvan Lloyd int *indexptr)
286a1ee3836SEvan Lloyd {
287a1ee3836SEvan Lloyd int result = RET_END_OPT_LIST;
288a1ee3836SEvan Lloyd
289a1ee3836SEvan Lloyd getopt_init();
290a1ee3836SEvan Lloyd /* If we have an argument left to play with */
291a1ee3836SEvan Lloyd if ((argc > optind) && (argv != 0)) {
292a1ee3836SEvan Lloyd const char *arg = argv[optind];
293a1ee3836SEvan Lloyd
294a1ee3836SEvan Lloyd if ((arg != 0) && (arg[0] == '-')) {
295a1ee3836SEvan Lloyd if (arg[1] == '-') {
296a1ee3836SEvan Lloyd /* Looks like a long option. */
297a1ee3836SEvan Lloyd result = getopt_1long(argc,
298a1ee3836SEvan Lloyd argv,
299a1ee3836SEvan Lloyd longopts,
300a1ee3836SEvan Lloyd &arg[2],
301a1ee3836SEvan Lloyd indexptr);
302a1ee3836SEvan Lloyd } else {
303a1ee3836SEvan Lloyd result = getopt_1long(argc,
304a1ee3836SEvan Lloyd argv,
305a1ee3836SEvan Lloyd longopts,
306a1ee3836SEvan Lloyd &arg[1],
307a1ee3836SEvan Lloyd indexptr);
308a1ee3836SEvan Lloyd if (result == RET_UNKNOWN_OPT) {
309a1ee3836SEvan Lloyd result = getopt_1char(argc,
310a1ee3836SEvan Lloyd argv,
311a1ee3836SEvan Lloyd shortopts,
312a1ee3836SEvan Lloyd arg[1]);
313a1ee3836SEvan Lloyd }
314a1ee3836SEvan Lloyd }
315a1ee3836SEvan Lloyd }
316a1ee3836SEvan Lloyd }
317a1ee3836SEvan Lloyd return result;
318a1ee3836SEvan Lloyd }
319