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 
19 /*
20  *	If a hyphen was found in get_option, this will handle the
21  *	range of numbers, M-N.  This will expand the range and insert
22  *	the values[M, M+1, ..., N] into the ints array in get_options.
23  */
24 
get_range(char ** str,int * pint)25 static int get_range(char **str, int *pint)
26 {
27 	int x, inc_counter, upper_range;
28 
29 	(*str)++;
30 	upper_range = simple_strtol((*str), NULL, 0);
31 	inc_counter = upper_range - *pint;
32 	for (x = *pint; x < upper_range; x++)
33 		*pint++ = x;
34 	return inc_counter;
35 }
36 
37 /**
38  *	get_option - Parse integer from an option string
39  *	@str: option string
40  *	@pint: (output) integer value parsed from @str
41  *
42  *	Read an int from an option string; if available accept a subsequent
43  *	comma as well.
44  *
45  *	Return values:
46  *	0 - no int in string
47  *	1 - int found, no subsequent comma
48  *	2 - int found including a subsequent comma
49  *	3 - hyphen found to denote a range
50  */
51 
get_option(char ** str,int * pint)52 int get_option (char **str, int *pint)
53 {
54 	char *cur = *str;
55 
56 	if (!cur || !(*cur))
57 		return 0;
58 	*pint = simple_strtol (cur, str, 0);
59 	if (cur == *str)
60 		return 0;
61 	if (**str == ',') {
62 		(*str)++;
63 		return 2;
64 	}
65 	if (**str == '-')
66 		return 3;
67 
68 	return 1;
69 }
70 
71 /**
72  *	get_options - Parse a string into a list of integers
73  *	@str: String to be parsed
74  *	@nints: size of integer array
75  *	@ints: integer array
76  *
77  *	This function parses a string containing a comma-separated
78  *	list of integers, a hyphen-separated range of _positive_ integers,
79  *	or a combination of both.  The parse halts when the array is
80  *	full, or when no more numbers can be retrieved from the
81  *	string.
82  *
83  *	Return value is the character in the string which caused
84  *	the parse to end (typically a null terminator, if @str is
85  *	completely parseable).
86  */
87 
get_options(const char * str,int nints,int * ints)88 char *get_options(const char *str, int nints, int *ints)
89 {
90 	int res, i = 1;
91 
92 	while (i < nints) {
93 		res = get_option ((char **)&str, ints + i);
94 		if (res == 0)
95 			break;
96 		if (res == 3) {
97 			int range_nums;
98 			range_nums = get_range((char **)&str, ints + i);
99 			if (range_nums < 0)
100 				break;
101 			/*
102 			 * Decrement the result by one to leave out the
103 			 * last number in the range.  The next iteration
104 			 * will handle the upper number in the range
105 			 */
106 			i += (range_nums - 1);
107 		}
108 		i++;
109 		if (res == 1)
110 			break;
111 	}
112 	ints[0] = i - 1;
113 	return (char *)str;
114 }
115 
116 /**
117  *	memparse - parse a string with mem suffixes into a number
118  *	@ptr: Where parse begins
119  *	@retptr: (output) Optional pointer to next char after parse completes
120  *
121  *	Parses a string into a number.  The number stored at @ptr is
122  *	potentially suffixed with %K (for kilobytes, or 1024 bytes),
123  *	%M (for megabytes, or 1048576 bytes), or %G (for gigabytes, or
124  *	1073741824).  If the number is suffixed with K, M, or G, then
125  *	the return value is the number multiplied by one kilobyte, one
126  *	megabyte, or one gigabyte, respectively.
127  */
128 
memparse(const char * ptr,char ** retptr)129 unsigned long long memparse(const char *ptr, char **retptr)
130 {
131 	char *endptr;	/* local pointer to end of parsed string */
132 
133 	unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
134 
135 	switch (*endptr) {
136 	case 'G':
137 	case 'g':
138 		ret <<= 10;
139 	case 'M':
140 	case 'm':
141 		ret <<= 10;
142 	case 'K':
143 	case 'k':
144 		ret <<= 10;
145 		endptr++;
146 	default:
147 		break;
148 	}
149 
150 	if (retptr)
151 		*retptr = endptr;
152 
153 	return ret;
154 }
155 
156 
157 EXPORT_SYMBOL(memparse);
158 EXPORT_SYMBOL(get_option);
159 EXPORT_SYMBOL(get_options);
160