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