xref: /DragonStub/apps/lib/cmdline.c (revision 78b790fa8bc8298f8bdfd5bd1945781650dbf361)
1*78b790faSLoGin // SPDX-License-Identifier: GPL-2.0-only
2*78b790faSLoGin /*
3*78b790faSLoGin  * linux/lib/cmdline.c
4*78b790faSLoGin  * Helper functions generally used for parsing kernel command line
5*78b790faSLoGin  * and module options.
6*78b790faSLoGin  *
7*78b790faSLoGin  * Code and copyrights come from init/main.c and arch/i386/kernel/setup.c.
8*78b790faSLoGin  *
9*78b790faSLoGin  * GNU Indent formatting options for this file: -kr -i8 -npsl -pcs
10*78b790faSLoGin  */
11*78b790faSLoGin 
12*78b790faSLoGin #include <dragonstub/linux/const.h>
13*78b790faSLoGin #include <dragonstub/dragonstub.h>
14*78b790faSLoGin #include <dragonstub/linux/ctype.h>
15*78b790faSLoGin 
16*78b790faSLoGin /*
17*78b790faSLoGin  *	If a hyphen was found in get_option, this will handle the
18*78b790faSLoGin  *	range of numbers, M-N.  This will expand the range and insert
19*78b790faSLoGin  *	the values[M, M+1, ..., N] into the ints array in get_options.
20*78b790faSLoGin  */
21*78b790faSLoGin 
get_range(char ** str,int * pint,int n)22*78b790faSLoGin static int get_range(char **str, int *pint, int n)
23*78b790faSLoGin {
24*78b790faSLoGin 	int x, inc_counter, upper_range;
25*78b790faSLoGin 
26*78b790faSLoGin 	(*str)++;
27*78b790faSLoGin 	upper_range = simple_strtol((*str), NULL, 0);
28*78b790faSLoGin 	inc_counter = upper_range - *pint;
29*78b790faSLoGin 	for (x = *pint; n && x < upper_range; x++, n--)
30*78b790faSLoGin 		*pint++ = x;
31*78b790faSLoGin 	return inc_counter;
32*78b790faSLoGin }
33*78b790faSLoGin 
34*78b790faSLoGin /**
35*78b790faSLoGin  *	get_option - Parse integer from an option string
36*78b790faSLoGin  *	@str: option string
37*78b790faSLoGin  *	@pint: (optional output) integer value parsed from @str
38*78b790faSLoGin  *
39*78b790faSLoGin  *	Read an int from an option string; if available accept a subsequent
40*78b790faSLoGin  *	comma as well.
41*78b790faSLoGin  *
42*78b790faSLoGin  *	When @pint is NULL the function can be used as a validator of
43*78b790faSLoGin  *	the current option in the string.
44*78b790faSLoGin  *
45*78b790faSLoGin  *	Return values:
46*78b790faSLoGin  *	0 - no int in string
47*78b790faSLoGin  *	1 - int found, no subsequent comma
48*78b790faSLoGin  *	2 - int found including a subsequent comma
49*78b790faSLoGin  *	3 - hyphen found to denote a range
50*78b790faSLoGin  *
51*78b790faSLoGin  *	Leading hyphen without integer is no integer case, but we consume it
52*78b790faSLoGin  *	for the sake of simplification.
53*78b790faSLoGin  */
54*78b790faSLoGin 
get_option(char ** str,int * pint)55*78b790faSLoGin int get_option(char **str, int *pint)
56*78b790faSLoGin {
57*78b790faSLoGin 	char *cur = *str;
58*78b790faSLoGin 	int value;
59*78b790faSLoGin 
60*78b790faSLoGin 	if (!cur || !(*cur))
61*78b790faSLoGin 		return 0;
62*78b790faSLoGin 	if (*cur == '-')
63*78b790faSLoGin 		value = -simple_strtoull(++cur, str, 0);
64*78b790faSLoGin 	else
65*78b790faSLoGin 		value = simple_strtoull(cur, str, 0);
66*78b790faSLoGin 	if (pint)
67*78b790faSLoGin 		*pint = value;
68*78b790faSLoGin 	if (cur == *str)
69*78b790faSLoGin 		return 0;
70*78b790faSLoGin 	if (**str == ',') {
71*78b790faSLoGin 		(*str)++;
72*78b790faSLoGin 		return 2;
73*78b790faSLoGin 	}
74*78b790faSLoGin 	if (**str == '-')
75*78b790faSLoGin 		return 3;
76*78b790faSLoGin 
77*78b790faSLoGin 	return 1;
78*78b790faSLoGin }
79*78b790faSLoGin 
80*78b790faSLoGin /**
81*78b790faSLoGin  *	get_options - Parse a string into a list of integers
82*78b790faSLoGin  *	@str: String to be parsed
83*78b790faSLoGin  *	@nints: size of integer array
84*78b790faSLoGin  *	@ints: integer array (must have room for at least one element)
85*78b790faSLoGin  *
86*78b790faSLoGin  *	This function parses a string containing a comma-separated
87*78b790faSLoGin  *	list of integers, a hyphen-separated range of _positive_ integers,
88*78b790faSLoGin  *	or a combination of both.  The parse halts when the array is
89*78b790faSLoGin  *	full, or when no more numbers can be retrieved from the
90*78b790faSLoGin  *	string.
91*78b790faSLoGin  *
92*78b790faSLoGin  *	When @nints is 0, the function just validates the given @str and
93*78b790faSLoGin  *	returns the amount of parseable integers as described below.
94*78b790faSLoGin  *
95*78b790faSLoGin  *	Returns:
96*78b790faSLoGin  *
97*78b790faSLoGin  *	The first element is filled by the number of collected integers
98*78b790faSLoGin  *	in the range. The rest is what was parsed from the @str.
99*78b790faSLoGin  *
100*78b790faSLoGin  *	Return value is the character in the string which caused
101*78b790faSLoGin  *	the parse to end (typically a null terminator, if @str is
102*78b790faSLoGin  *	completely parseable).
103*78b790faSLoGin  */
104*78b790faSLoGin 
get_options(const char * str,int nints,int * ints)105*78b790faSLoGin char *get_options(const char *str, int nints, int *ints)
106*78b790faSLoGin {
107*78b790faSLoGin 	bool validate = (nints == 0);
108*78b790faSLoGin 	int res, i = 1;
109*78b790faSLoGin 
110*78b790faSLoGin 	while (i < nints || validate) {
111*78b790faSLoGin 		int *pint = validate ? ints : ints + i;
112*78b790faSLoGin 
113*78b790faSLoGin 		res = get_option((char **)&str, pint);
114*78b790faSLoGin 		if (res == 0)
115*78b790faSLoGin 			break;
116*78b790faSLoGin 		if (res == 3) {
117*78b790faSLoGin 			int n = validate ? 0 : nints - i;
118*78b790faSLoGin 			int range_nums;
119*78b790faSLoGin 
120*78b790faSLoGin 			range_nums = get_range((char **)&str, pint, n);
121*78b790faSLoGin 			if (range_nums < 0)
122*78b790faSLoGin 				break;
123*78b790faSLoGin 			/*
124*78b790faSLoGin 			 * Decrement the result by one to leave out the
125*78b790faSLoGin 			 * last number in the range.  The next iteration
126*78b790faSLoGin 			 * will handle the upper number in the range
127*78b790faSLoGin 			 */
128*78b790faSLoGin 			i += (range_nums - 1);
129*78b790faSLoGin 		}
130*78b790faSLoGin 		i++;
131*78b790faSLoGin 		if (res == 1)
132*78b790faSLoGin 			break;
133*78b790faSLoGin 	}
134*78b790faSLoGin 	ints[0] = i - 1;
135*78b790faSLoGin 	return (char *)str;
136*78b790faSLoGin }
137*78b790faSLoGin 
138*78b790faSLoGin /**
139*78b790faSLoGin  *	memparse - parse a string with mem suffixes into a number
140*78b790faSLoGin  *	@ptr: Where parse begins
141*78b790faSLoGin  *	@retptr: (output) Optional pointer to next char after parse completes
142*78b790faSLoGin  *
143*78b790faSLoGin  *	Parses a string into a number.  The number stored at @ptr is
144*78b790faSLoGin  *	potentially suffixed with K, M, G, T, P, E.
145*78b790faSLoGin  */
146*78b790faSLoGin 
memparse(const char * ptr,char ** retptr)147*78b790faSLoGin unsigned long long memparse(const char *ptr, char **retptr)
148*78b790faSLoGin {
149*78b790faSLoGin 	char *endptr; /* local pointer to end of parsed string */
150*78b790faSLoGin 
151*78b790faSLoGin 	unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
152*78b790faSLoGin 
153*78b790faSLoGin 	switch (*endptr) {
154*78b790faSLoGin 	case 'E':
155*78b790faSLoGin 	case 'e':
156*78b790faSLoGin 		ret <<= 10;
157*78b790faSLoGin 		fallthrough;
158*78b790faSLoGin 	case 'P':
159*78b790faSLoGin 	case 'p':
160*78b790faSLoGin 		ret <<= 10;
161*78b790faSLoGin 		fallthrough;
162*78b790faSLoGin 	case 'T':
163*78b790faSLoGin 	case 't':
164*78b790faSLoGin 		ret <<= 10;
165*78b790faSLoGin 		fallthrough;
166*78b790faSLoGin 	case 'G':
167*78b790faSLoGin 	case 'g':
168*78b790faSLoGin 		ret <<= 10;
169*78b790faSLoGin 		fallthrough;
170*78b790faSLoGin 	case 'M':
171*78b790faSLoGin 	case 'm':
172*78b790faSLoGin 		ret <<= 10;
173*78b790faSLoGin 		fallthrough;
174*78b790faSLoGin 	case 'K':
175*78b790faSLoGin 	case 'k':
176*78b790faSLoGin 		ret <<= 10;
177*78b790faSLoGin 		endptr++;
178*78b790faSLoGin 		fallthrough;
179*78b790faSLoGin 	default:
180*78b790faSLoGin 		break;
181*78b790faSLoGin 	}
182*78b790faSLoGin 
183*78b790faSLoGin 	if (retptr)
184*78b790faSLoGin 		*retptr = endptr;
185*78b790faSLoGin 
186*78b790faSLoGin 	return ret;
187*78b790faSLoGin }
188*78b790faSLoGin 
189*78b790faSLoGin 
190*78b790faSLoGin /*
191*78b790faSLoGin  * Parse a string to get a param value pair.
192*78b790faSLoGin  * You can use " around spaces, but can't escape ".
193*78b790faSLoGin  * Hyphens and underscores equivalent in parameter names.
194*78b790faSLoGin  */
next_arg(char * args,char ** param,char ** val)195*78b790faSLoGin char *next_arg(char *args, char **param, char **val)
196*78b790faSLoGin {
197*78b790faSLoGin 	unsigned int i, equals = 0;
198*78b790faSLoGin 	int in_quote = 0, quoted = 0;
199*78b790faSLoGin 
200*78b790faSLoGin 	if (*args == '"') {
201*78b790faSLoGin 		args++;
202*78b790faSLoGin 		in_quote = 1;
203*78b790faSLoGin 		quoted = 1;
204*78b790faSLoGin 	}
205*78b790faSLoGin 
206*78b790faSLoGin 	for (i = 0; args[i]; i++) {
207*78b790faSLoGin 		if (isspace(args[i]) && !in_quote)
208*78b790faSLoGin 			break;
209*78b790faSLoGin 		if (equals == 0) {
210*78b790faSLoGin 			if (args[i] == '=')
211*78b790faSLoGin 				equals = i;
212*78b790faSLoGin 		}
213*78b790faSLoGin 		if (args[i] == '"')
214*78b790faSLoGin 			in_quote = !in_quote;
215*78b790faSLoGin 	}
216*78b790faSLoGin 
217*78b790faSLoGin 	*param = args;
218*78b790faSLoGin 	if (!equals)
219*78b790faSLoGin 		*val = NULL;
220*78b790faSLoGin 	else {
221*78b790faSLoGin 		args[equals] = '\0';
222*78b790faSLoGin 		*val = args + equals + 1;
223*78b790faSLoGin 
224*78b790faSLoGin 		/* Don't include quotes in value. */
225*78b790faSLoGin 		if (**val == '"') {
226*78b790faSLoGin 			(*val)++;
227*78b790faSLoGin 			if (args[i - 1] == '"')
228*78b790faSLoGin 				args[i - 1] = '\0';
229*78b790faSLoGin 		}
230*78b790faSLoGin 	}
231*78b790faSLoGin 	if (quoted && i > 0 && args[i - 1] == '"')
232*78b790faSLoGin 		args[i - 1] = '\0';
233*78b790faSLoGin 
234*78b790faSLoGin 	if (args[i]) {
235*78b790faSLoGin 		args[i] = '\0';
236*78b790faSLoGin 		args += i + 1;
237*78b790faSLoGin 	} else
238*78b790faSLoGin 		args += i;
239*78b790faSLoGin 
240*78b790faSLoGin 	/* Chew up trailing spaces. */
241*78b790faSLoGin 	return skip_spaces(args);
242*78b790faSLoGin }
243