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