xref: /aosp_15_r20/external/flashrom/cli_getopt.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker  * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker  * It comes originally from the musl libc project and is licensed under the
4*0d6140beSAndroid Build Coastguard Worker  * terms of the MIT license.
5*0d6140beSAndroid Build Coastguard Worker  *
6*0d6140beSAndroid Build Coastguard Worker  * Copyringht (C) 2023 Rich Felker and the musl authors
7*0d6140beSAndroid Build Coastguard Worker  * Adjusted for flashrom by Thomas Heijligen<[email protected]>
8*0d6140beSAndroid Build Coastguard Worker  *
9*0d6140beSAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a copy
10*0d6140beSAndroid Build Coastguard Worker  * of this software and associated documentation files (the "Software"), to deal
11*0d6140beSAndroid Build Coastguard Worker  * in the Software without restriction, including without limitation the rights
12*0d6140beSAndroid Build Coastguard Worker  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13*0d6140beSAndroid Build Coastguard Worker  * copies of the Software, and to permit persons to whom the Software is
14*0d6140beSAndroid Build Coastguard Worker  * furnished to do so, subject to the following conditions:
15*0d6140beSAndroid Build Coastguard Worker  *
16*0d6140beSAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included in
17*0d6140beSAndroid Build Coastguard Worker  * all copies or substantial portions of the Software.
18*0d6140beSAndroid Build Coastguard Worker  *
19*0d6140beSAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20*0d6140beSAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21*0d6140beSAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22*0d6140beSAndroid Build Coastguard Worker  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23*0d6140beSAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24*0d6140beSAndroid Build Coastguard Worker  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25*0d6140beSAndroid Build Coastguard Worker  * SOFTWARE.
26*0d6140beSAndroid Build Coastguard Worker  */
27*0d6140beSAndroid Build Coastguard Worker 
28*0d6140beSAndroid Build Coastguard Worker #include <unistd.h>
29*0d6140beSAndroid Build Coastguard Worker #include <wchar.h>
30*0d6140beSAndroid Build Coastguard Worker #include <string.h>
31*0d6140beSAndroid Build Coastguard Worker #include <limits.h>
32*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
33*0d6140beSAndroid Build Coastguard Worker #include "cli_classic.h"
34*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
35*0d6140beSAndroid Build Coastguard Worker 
36*0d6140beSAndroid Build Coastguard Worker char *optarg;
37*0d6140beSAndroid Build Coastguard Worker int optind=1, opterr=1, optopt, optpos;
38*0d6140beSAndroid Build Coastguard Worker 
getopt_msg(const char * a,const char * b,const char * c,size_t l)39*0d6140beSAndroid Build Coastguard Worker static void getopt_msg(const char *a, const char *b, const char *c, size_t l)
40*0d6140beSAndroid Build Coastguard Worker {
41*0d6140beSAndroid Build Coastguard Worker 	msg_gerr("%s%s%*c\n", a, b, l, c);
42*0d6140beSAndroid Build Coastguard Worker }
43*0d6140beSAndroid Build Coastguard Worker 
getopt(int argc,char * const argv[],const char * optstring)44*0d6140beSAndroid Build Coastguard Worker int getopt(int argc, char * const argv[], const char *optstring)
45*0d6140beSAndroid Build Coastguard Worker {
46*0d6140beSAndroid Build Coastguard Worker 	int i;
47*0d6140beSAndroid Build Coastguard Worker 	wchar_t c, d;
48*0d6140beSAndroid Build Coastguard Worker 	int k, l;
49*0d6140beSAndroid Build Coastguard Worker 	char *optchar;
50*0d6140beSAndroid Build Coastguard Worker 
51*0d6140beSAndroid Build Coastguard Worker 	if (!optind) {
52*0d6140beSAndroid Build Coastguard Worker 		optind = 1;
53*0d6140beSAndroid Build Coastguard Worker 		optpos = 0;
54*0d6140beSAndroid Build Coastguard Worker 	}
55*0d6140beSAndroid Build Coastguard Worker 
56*0d6140beSAndroid Build Coastguard Worker 	if (optind >= argc || !argv[optind])
57*0d6140beSAndroid Build Coastguard Worker 		return -1;
58*0d6140beSAndroid Build Coastguard Worker 
59*0d6140beSAndroid Build Coastguard Worker 	if (argv[optind][0] != '-') {
60*0d6140beSAndroid Build Coastguard Worker 		if (optstring[0] == '-') {
61*0d6140beSAndroid Build Coastguard Worker 			optarg = argv[optind++];
62*0d6140beSAndroid Build Coastguard Worker 			return 1;
63*0d6140beSAndroid Build Coastguard Worker 		}
64*0d6140beSAndroid Build Coastguard Worker 		return -1;
65*0d6140beSAndroid Build Coastguard Worker 	}
66*0d6140beSAndroid Build Coastguard Worker 
67*0d6140beSAndroid Build Coastguard Worker 	if (!argv[optind][1])
68*0d6140beSAndroid Build Coastguard Worker 		return -1;
69*0d6140beSAndroid Build Coastguard Worker 
70*0d6140beSAndroid Build Coastguard Worker 	if (argv[optind][1] == '-' && !argv[optind][2])
71*0d6140beSAndroid Build Coastguard Worker 		return optind++, -1;
72*0d6140beSAndroid Build Coastguard Worker 
73*0d6140beSAndroid Build Coastguard Worker 	if (!optpos)
74*0d6140beSAndroid Build Coastguard Worker 		optpos++;
75*0d6140beSAndroid Build Coastguard Worker 	if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) {
76*0d6140beSAndroid Build Coastguard Worker 		k = 1;
77*0d6140beSAndroid Build Coastguard Worker 		c = 0xfffd; /* replacement char */
78*0d6140beSAndroid Build Coastguard Worker 	}
79*0d6140beSAndroid Build Coastguard Worker 	optchar = argv[optind]+optpos;
80*0d6140beSAndroid Build Coastguard Worker 	optpos += k;
81*0d6140beSAndroid Build Coastguard Worker 
82*0d6140beSAndroid Build Coastguard Worker 	if (!argv[optind][optpos]) {
83*0d6140beSAndroid Build Coastguard Worker 		optind++;
84*0d6140beSAndroid Build Coastguard Worker 		optpos = 0;
85*0d6140beSAndroid Build Coastguard Worker 	}
86*0d6140beSAndroid Build Coastguard Worker 
87*0d6140beSAndroid Build Coastguard Worker 	if (optstring[0] == '-' || optstring[0] == '+')
88*0d6140beSAndroid Build Coastguard Worker 		optstring++;
89*0d6140beSAndroid Build Coastguard Worker 
90*0d6140beSAndroid Build Coastguard Worker 	i = 0;
91*0d6140beSAndroid Build Coastguard Worker 	d = 0;
92*0d6140beSAndroid Build Coastguard Worker 	do {
93*0d6140beSAndroid Build Coastguard Worker 		l = mbtowc(&d, optstring+i, MB_LEN_MAX);
94*0d6140beSAndroid Build Coastguard Worker 		if (l>0) i+=l; else i++;
95*0d6140beSAndroid Build Coastguard Worker 	} while (l && d != c);
96*0d6140beSAndroid Build Coastguard Worker 
97*0d6140beSAndroid Build Coastguard Worker 	if (d != c || c == ':') {
98*0d6140beSAndroid Build Coastguard Worker 		optopt = c;
99*0d6140beSAndroid Build Coastguard Worker 		if (optstring[0] != ':' && opterr)
100*0d6140beSAndroid Build Coastguard Worker 			getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
101*0d6140beSAndroid Build Coastguard Worker 		return '?';
102*0d6140beSAndroid Build Coastguard Worker 	}
103*0d6140beSAndroid Build Coastguard Worker 	if (optstring[i] == ':') {
104*0d6140beSAndroid Build Coastguard Worker 		optarg = 0;
105*0d6140beSAndroid Build Coastguard Worker 		if (optstring[i+1] != ':' || optpos) {
106*0d6140beSAndroid Build Coastguard Worker 			optarg = argv[optind++] + optpos;
107*0d6140beSAndroid Build Coastguard Worker 			optpos = 0;
108*0d6140beSAndroid Build Coastguard Worker 		}
109*0d6140beSAndroid Build Coastguard Worker 		if (optind > argc) {
110*0d6140beSAndroid Build Coastguard Worker 			optopt = c;
111*0d6140beSAndroid Build Coastguard Worker 			if (optstring[0] == ':')
112*0d6140beSAndroid Build Coastguard Worker 				return ':';
113*0d6140beSAndroid Build Coastguard Worker 			if (opterr) getopt_msg(argv[0],
114*0d6140beSAndroid Build Coastguard Worker 				": option requires an argument: ",
115*0d6140beSAndroid Build Coastguard Worker 				optchar, k);
116*0d6140beSAndroid Build Coastguard Worker 			return '?';
117*0d6140beSAndroid Build Coastguard Worker 		}
118*0d6140beSAndroid Build Coastguard Worker 	}
119*0d6140beSAndroid Build Coastguard Worker 	return c;
120*0d6140beSAndroid Build Coastguard Worker }
121*0d6140beSAndroid Build Coastguard Worker 
__getopt_long_core(int argc,char * const * argv,const char * optstring,const struct option * longopts,int * idx,int longonly)122*0d6140beSAndroid Build Coastguard Worker static int __getopt_long_core(int argc, char *const *argv, const char *optstring,
123*0d6140beSAndroid Build Coastguard Worker 		const struct option *longopts, int *idx, int longonly)
124*0d6140beSAndroid Build Coastguard Worker {
125*0d6140beSAndroid Build Coastguard Worker 	optarg = 0;
126*0d6140beSAndroid Build Coastguard Worker 	if (longopts && argv[optind][0] == '-' &&
127*0d6140beSAndroid Build Coastguard Worker 		((longonly && argv[optind][1] && argv[optind][1] != '-') ||
128*0d6140beSAndroid Build Coastguard Worker 		 (argv[optind][1] == '-' && argv[optind][2])))
129*0d6140beSAndroid Build Coastguard Worker 	{
130*0d6140beSAndroid Build Coastguard Worker 		int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':';
131*0d6140beSAndroid Build Coastguard Worker 		int i, cnt, match = 0;
132*0d6140beSAndroid Build Coastguard Worker 		char *arg = NULL, *opt, *start = argv[optind]+1;
133*0d6140beSAndroid Build Coastguard Worker 		for (cnt=i=0; longopts[i].name; i++) {
134*0d6140beSAndroid Build Coastguard Worker 			const char *name = longopts[i].name;
135*0d6140beSAndroid Build Coastguard Worker 			opt = start;
136*0d6140beSAndroid Build Coastguard Worker 			if (*opt == '-') opt++;
137*0d6140beSAndroid Build Coastguard Worker 			while (*opt && *opt != '=' && *opt == *name)
138*0d6140beSAndroid Build Coastguard Worker 				name++, opt++;
139*0d6140beSAndroid Build Coastguard Worker 			if (*opt && *opt != '=') continue;
140*0d6140beSAndroid Build Coastguard Worker 			arg = opt;
141*0d6140beSAndroid Build Coastguard Worker 			match = i;
142*0d6140beSAndroid Build Coastguard Worker 			if (!*name) {
143*0d6140beSAndroid Build Coastguard Worker 				cnt = 1;
144*0d6140beSAndroid Build Coastguard Worker 				break;
145*0d6140beSAndroid Build Coastguard Worker 			}
146*0d6140beSAndroid Build Coastguard Worker 			cnt++;
147*0d6140beSAndroid Build Coastguard Worker 		}
148*0d6140beSAndroid Build Coastguard Worker 		if (cnt==1 && longonly && arg-start == mblen(start, MB_LEN_MAX)) {
149*0d6140beSAndroid Build Coastguard Worker 			int l = arg-start;
150*0d6140beSAndroid Build Coastguard Worker 			for (i=0; optstring[i]; i++) {
151*0d6140beSAndroid Build Coastguard Worker 				int j;
152*0d6140beSAndroid Build Coastguard Worker 				for (j=0; j<l && start[j]==optstring[i+j]; j++);
153*0d6140beSAndroid Build Coastguard Worker 				if (j==l) {
154*0d6140beSAndroid Build Coastguard Worker 					cnt++;
155*0d6140beSAndroid Build Coastguard Worker 					break;
156*0d6140beSAndroid Build Coastguard Worker 				}
157*0d6140beSAndroid Build Coastguard Worker 			}
158*0d6140beSAndroid Build Coastguard Worker 		}
159*0d6140beSAndroid Build Coastguard Worker 		if (cnt==1) {
160*0d6140beSAndroid Build Coastguard Worker 			i = match;
161*0d6140beSAndroid Build Coastguard Worker 			opt = arg;
162*0d6140beSAndroid Build Coastguard Worker 			optind++;
163*0d6140beSAndroid Build Coastguard Worker 			if (*opt == '=') {
164*0d6140beSAndroid Build Coastguard Worker 				if (!longopts[i].has_arg) {
165*0d6140beSAndroid Build Coastguard Worker 					optopt = longopts[i].val;
166*0d6140beSAndroid Build Coastguard Worker 					if (colon || !opterr)
167*0d6140beSAndroid Build Coastguard Worker 						return '?';
168*0d6140beSAndroid Build Coastguard Worker 					getopt_msg(argv[0],
169*0d6140beSAndroid Build Coastguard Worker 						": option does not take an argument: ",
170*0d6140beSAndroid Build Coastguard Worker 						longopts[i].name,
171*0d6140beSAndroid Build Coastguard Worker 						strlen(longopts[i].name));
172*0d6140beSAndroid Build Coastguard Worker 					return '?';
173*0d6140beSAndroid Build Coastguard Worker 				}
174*0d6140beSAndroid Build Coastguard Worker 				optarg = opt+1;
175*0d6140beSAndroid Build Coastguard Worker 			} else if (longopts[i].has_arg == required_argument) {
176*0d6140beSAndroid Build Coastguard Worker 				if (!(optarg = argv[optind])) {
177*0d6140beSAndroid Build Coastguard Worker 					optopt = longopts[i].val;
178*0d6140beSAndroid Build Coastguard Worker 					if (colon) return ':';
179*0d6140beSAndroid Build Coastguard Worker 					if (!opterr) return '?';
180*0d6140beSAndroid Build Coastguard Worker 					getopt_msg(argv[0],
181*0d6140beSAndroid Build Coastguard Worker 						": option requires an argument: ",
182*0d6140beSAndroid Build Coastguard Worker 						longopts[i].name,
183*0d6140beSAndroid Build Coastguard Worker 						strlen(longopts[i].name));
184*0d6140beSAndroid Build Coastguard Worker 					return '?';
185*0d6140beSAndroid Build Coastguard Worker 				}
186*0d6140beSAndroid Build Coastguard Worker 				optind++;
187*0d6140beSAndroid Build Coastguard Worker 			}
188*0d6140beSAndroid Build Coastguard Worker 			if (idx)
189*0d6140beSAndroid Build Coastguard Worker 				*idx = i;
190*0d6140beSAndroid Build Coastguard Worker 			if (longopts[i].flag) {
191*0d6140beSAndroid Build Coastguard Worker 				*longopts[i].flag = longopts[i].val;
192*0d6140beSAndroid Build Coastguard Worker 				return 0;
193*0d6140beSAndroid Build Coastguard Worker 			}
194*0d6140beSAndroid Build Coastguard Worker 			return longopts[i].val;
195*0d6140beSAndroid Build Coastguard Worker 		}
196*0d6140beSAndroid Build Coastguard Worker 		if (argv[optind][1] == '-') {
197*0d6140beSAndroid Build Coastguard Worker 			optopt = 0;
198*0d6140beSAndroid Build Coastguard Worker 			if (!colon && opterr)
199*0d6140beSAndroid Build Coastguard Worker 				getopt_msg(argv[0], cnt ?
200*0d6140beSAndroid Build Coastguard Worker 					": option is ambiguous: " :
201*0d6140beSAndroid Build Coastguard Worker 					": unrecognized option: ",
202*0d6140beSAndroid Build Coastguard Worker 					argv[optind]+2,
203*0d6140beSAndroid Build Coastguard Worker 					strlen(argv[optind]+2));
204*0d6140beSAndroid Build Coastguard Worker 			optind++;
205*0d6140beSAndroid Build Coastguard Worker 			return '?';
206*0d6140beSAndroid Build Coastguard Worker 		}
207*0d6140beSAndroid Build Coastguard Worker 	}
208*0d6140beSAndroid Build Coastguard Worker 	return getopt(argc, argv, optstring);
209*0d6140beSAndroid Build Coastguard Worker }
210*0d6140beSAndroid Build Coastguard Worker 
permute(char * const * argv,int dest,int src)211*0d6140beSAndroid Build Coastguard Worker static void permute(char *const *argv, int dest, int src)
212*0d6140beSAndroid Build Coastguard Worker {
213*0d6140beSAndroid Build Coastguard Worker 	char **av = (char **)argv;
214*0d6140beSAndroid Build Coastguard Worker 	char *tmp = av[src];
215*0d6140beSAndroid Build Coastguard Worker 	int i;
216*0d6140beSAndroid Build Coastguard Worker 	for (i=src; i>dest; i--)
217*0d6140beSAndroid Build Coastguard Worker 		av[i] = av[i-1];
218*0d6140beSAndroid Build Coastguard Worker 	av[dest] = tmp;
219*0d6140beSAndroid Build Coastguard Worker }
220*0d6140beSAndroid Build Coastguard Worker 
__getopt_long(int argc,char * const * argv,const char * optstring,const struct option * longopts,int * idx,int longonly)221*0d6140beSAndroid Build Coastguard Worker static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
222*0d6140beSAndroid Build Coastguard Worker {
223*0d6140beSAndroid Build Coastguard Worker 	int ret, skipped, resumed;
224*0d6140beSAndroid Build Coastguard Worker 	if (!optind) {
225*0d6140beSAndroid Build Coastguard Worker 		optind = 1;
226*0d6140beSAndroid Build Coastguard Worker 		optpos = 0;
227*0d6140beSAndroid Build Coastguard Worker 	}
228*0d6140beSAndroid Build Coastguard Worker 
229*0d6140beSAndroid Build Coastguard Worker 	if (optind >= argc || !argv[optind])
230*0d6140beSAndroid Build Coastguard Worker 		return -1;
231*0d6140beSAndroid Build Coastguard Worker 	skipped = optind;
232*0d6140beSAndroid Build Coastguard Worker 	if (optstring[0] != '+' && optstring[0] != '-') {
233*0d6140beSAndroid Build Coastguard Worker 		int i;
234*0d6140beSAndroid Build Coastguard Worker 		for (i=optind; ; i++) {
235*0d6140beSAndroid Build Coastguard Worker 			if (i >= argc || !argv[i])
236*0d6140beSAndroid Build Coastguard Worker 				return -1;
237*0d6140beSAndroid Build Coastguard Worker 			if (argv[i][0] == '-' && argv[i][1])
238*0d6140beSAndroid Build Coastguard Worker 				break;
239*0d6140beSAndroid Build Coastguard Worker 		}
240*0d6140beSAndroid Build Coastguard Worker 		optind = i;
241*0d6140beSAndroid Build Coastguard Worker 	}
242*0d6140beSAndroid Build Coastguard Worker 	resumed = optind;
243*0d6140beSAndroid Build Coastguard Worker 	ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
244*0d6140beSAndroid Build Coastguard Worker 	if (resumed > skipped) {
245*0d6140beSAndroid Build Coastguard Worker 		int i, cnt = optind-resumed;
246*0d6140beSAndroid Build Coastguard Worker 		for (i=0; i<cnt; i++)
247*0d6140beSAndroid Build Coastguard Worker 			permute(argv, skipped, optind-1);
248*0d6140beSAndroid Build Coastguard Worker 		optind = skipped + cnt;
249*0d6140beSAndroid Build Coastguard Worker 	}
250*0d6140beSAndroid Build Coastguard Worker 	return ret;
251*0d6140beSAndroid Build Coastguard Worker }
252*0d6140beSAndroid Build Coastguard Worker 
getopt_long(int argc,char * const * argv,const char * optstring,const struct option * longopts,int * idx)253*0d6140beSAndroid Build Coastguard Worker int getopt_long(int argc, char *const *argv, const char *optstring,
254*0d6140beSAndroid Build Coastguard Worker 		const struct option *longopts, int *idx)
255*0d6140beSAndroid Build Coastguard Worker {
256*0d6140beSAndroid Build Coastguard Worker 	return __getopt_long(argc, argv, optstring, longopts, idx, 0);
257*0d6140beSAndroid Build Coastguard Worker }
258*0d6140beSAndroid Build Coastguard Worker 
getopt_long_only(int argc,char * const * argv,const char * optstring,const struct option * longopts,int * idx)259*0d6140beSAndroid Build Coastguard Worker int getopt_long_only(int argc, char *const *argv, const char *optstring,
260*0d6140beSAndroid Build Coastguard Worker 		const struct option *longopts, int *idx)
261*0d6140beSAndroid Build Coastguard Worker {
262*0d6140beSAndroid Build Coastguard Worker 	return __getopt_long(argc, argv, optstring, longopts, idx, 1);
263*0d6140beSAndroid Build Coastguard Worker }
264