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