parse.c revision 17abbe89b8d3a4c7a4deab00a7cc98fbd215f1ef
1/*
2 * This file contains the ini and command liner parser main.
3 */
4#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <ctype.h>
8#include <string.h>
9#include <errno.h>
10#include <limits.h>
11
12#include "parse.h"
13
14static unsigned long get_mult_time(char c)
15{
16	switch (c) {
17		case 'm':
18		case 'M':
19			return 60;
20		case 'h':
21		case 'H':
22			return 60 * 60;
23		case 'd':
24		case 'D':
25			return 24 * 60 * 60;
26		default:
27			return 1;
28	}
29}
30
31static unsigned long get_mult_bytes(char c)
32{
33	switch (c) {
34		case 'k':
35		case 'K':
36			return 1024;
37		case 'm':
38		case 'M':
39			return 1024 * 1024;
40		case 'g':
41		case 'G':
42			return 1024 * 1024 * 1024;
43		default:
44			return 1;
45	}
46}
47
48/*
49 * convert string into decimal value, noting any size suffix
50 */
51static int str_to_decimal(const char *str, unsigned long long *val, int kilo)
52{
53	int len;
54
55	len = strlen(str);
56	if (!len)
57		return 1;
58
59	*val = strtoul(str, NULL, 10);
60	if (*val == ULONG_MAX && errno == ERANGE)
61		return 1;
62
63	if (kilo)
64		*val *= get_mult_bytes(str[len - 1]);
65	else
66		*val *= get_mult_time(str[len - 1]);
67	return 0;
68}
69
70static int check_str_bytes(const char *p, unsigned long long *val)
71{
72	return str_to_decimal(p, val, 1);
73}
74
75static int check_str_time(const char *p, unsigned long long *val)
76{
77	return str_to_decimal(p, val, 0);
78}
79
80void strip_blank_front(char **p)
81{
82	char *s = *p;
83
84	while (isspace(*s))
85		s++;
86}
87
88void strip_blank_end(char *p)
89{
90	char *s = p + strlen(p) - 1;
91
92	while (isspace(*s) || iscntrl(*s))
93		s--;
94
95	*(s + 1) = '\0';
96}
97
98static int check_range_bytes(const char *str, unsigned long *val)
99{
100	char suffix;
101
102	if (sscanf(str, "%lu%c", val, &suffix) == 2) {
103		*val *= get_mult_bytes(suffix);
104		return 0;
105	}
106
107	if (sscanf(str, "%lu", val) == 1)
108		return 0;
109
110	return 1;
111}
112
113static int check_int(const char *p, unsigned int *val)
114{
115	if (sscanf(p, "%u", val) == 1)
116		return 0;
117
118	return 1;
119}
120
121static struct fio_option *find_option(struct fio_option *options,
122				      const char *opt)
123{
124	struct fio_option *o = &options[0];
125
126	while (o->name) {
127		if (!strcmp(o->name, opt))
128			return o;
129
130		o++;
131	}
132
133	return NULL;
134}
135
136#define val_store(ptr, val, off, data)			\
137	do {						\
138		ptr = td_var((data), (off));		\
139		*ptr = (val);				\
140	} while (0)
141
142static int __handle_option(struct fio_option *o, const char *ptr, void *data,
143			   int first)
144{
145	unsigned int il, *ilp;
146	unsigned long long ull, *ullp;
147	unsigned long ul1, ul2;
148	char **cp;
149	int ret = 0, is_time = 0;
150
151	switch (o->type) {
152	case FIO_OPT_STR: {
153		fio_opt_str_fn *fn = o->cb;
154
155		ret = fn(data, ptr);
156		break;
157	}
158	case FIO_OPT_STR_VAL_TIME:
159		is_time = 1;
160	case FIO_OPT_STR_VAL:
161	case FIO_OPT_STR_VAL_INT: {
162		fio_opt_str_val_fn *fn = o->cb;
163
164		if (is_time)
165			ret = check_str_time(ptr, &ull);
166		else
167			ret = check_str_bytes(ptr, &ull);
168
169		if (ret)
170			break;
171
172		if (o->max_val && ull > o->max_val)
173			ull = o->max_val;
174
175		if (fn)
176			ret = fn(data, &ull);
177		else {
178			if (o->type == FIO_OPT_STR_VAL_INT) {
179				if (first)
180					val_store(ilp, ull, o->off1, data);
181				if (o->off2)
182					val_store(ilp, ull, o->off2, data);
183			} else {
184				if (first)
185					val_store(ullp, ull, o->off1, data);
186				if (o->off2)
187					val_store(ullp, ull, o->off2, data);
188			}
189		}
190		break;
191	}
192	case FIO_OPT_STR_STORE:
193		cp = td_var(data, o->off1);
194		*cp = strdup(ptr);
195		break;
196	case FIO_OPT_RANGE: {
197		char tmp[128];
198		char *p1, *p2;
199
200		strncpy(tmp, ptr, sizeof(tmp) - 1);
201
202		p1 = strchr(tmp, '-');
203		if (!p1) {
204			ret = 1;
205			break;
206		}
207
208		p2 = p1 + 1;
209		*p1 = '\0';
210		p1 = tmp;
211
212		ret = 1;
213		if (!check_range_bytes(p1, &ul1) && !check_range_bytes(p2, &ul2)) {
214			ret = 0;
215			if (ul1 > ul2) {
216				unsigned long foo = ul1;
217
218				ul1 = ul2;
219				ul2 = foo;
220			}
221
222			if (first) {
223				val_store(ilp, ul1, o->off1, data);
224				val_store(ilp, ul2, o->off2, data);
225			}
226			if (o->off3 && o->off4) {
227				val_store(ilp, ul1, o->off3, data);
228				val_store(ilp, ul2, o->off4, data);
229			}
230		}
231
232		break;
233	}
234	case FIO_OPT_INT: {
235		fio_opt_int_fn *fn = o->cb;
236
237		ret = check_int(ptr, &il);
238		if (ret)
239			break;
240
241		if (o->max_val && il > o->max_val)
242			il = o->max_val;
243
244		if (fn)
245			ret = fn(data, &il);
246		else {
247			if (first)
248				val_store(ilp, il, o->off1, data);
249			if (o->off2)
250				val_store(ilp, il, o->off2, data);
251		}
252		break;
253	}
254	case FIO_OPT_STR_SET: {
255		fio_opt_str_set_fn *fn = o->cb;
256
257		if (fn)
258			ret = fn(data);
259		else {
260			if (first)
261				val_store(ilp, 1, o->off1, data);
262			if (o->off2)
263				val_store(ilp, 1, o->off2, data);
264		}
265		break;
266	}
267	default:
268		fprintf(stderr, "Bad option type %d\n", o->type);
269		ret = 1;
270	}
271
272	return ret;
273}
274
275static int handle_option(struct fio_option *o, const char *ptr, void *data)
276{
277	const char *ptr2;
278	int ret;
279
280	ret = __handle_option(o, ptr, data, 1);
281	if (ret)
282		return ret;
283
284	/*
285	 * See if we have a second set of parameters, hidden after a comma
286	 */
287	ptr2 = strchr(ptr, ',');
288	if (!ptr2)
289		return 0;
290
291	ptr2++;
292	return __handle_option(o, ptr2, data, 0);
293}
294
295int parse_cmd_option(const char *opt, const char *val,
296		     struct fio_option *options, void *data)
297{
298	struct fio_option *o;
299
300	o = find_option(options, opt);
301	if (!o) {
302		fprintf(stderr, "Bad option %s\n", opt);
303		return 1;
304	}
305
306	if (!handle_option(o, val, data))
307		return 0;
308
309	fprintf(stderr, "fio: failed parsing %s=%s\n", opt, val);
310	return 1;
311}
312
313int parse_option(const char *opt, struct fio_option *options, void *data)
314{
315	struct fio_option *o;
316	char *pre, *post;
317	char tmp[64];
318
319	strncpy(tmp, opt, sizeof(tmp) - 1);
320
321	pre = strchr(tmp, '=');
322	if (pre) {
323		post = pre;
324		*pre = '\0';
325		pre = tmp;
326		post++;
327		o = find_option(options, pre);
328	} else {
329		o = find_option(options, tmp);
330		post = NULL;
331	}
332
333	if (!o) {
334		fprintf(stderr, "Bad option %s\n", tmp);
335		return 1;
336	}
337
338	if (!handle_option(o, post, data))
339		return 0;
340
341	fprintf(stderr, "fio: failed parsing %s\n", opt);
342	return 1;
343}
344