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