[PATCH] parse cleanups
[fio.git] / parse.c
CommitLineData
cb2c86fd
JA
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/*
e1f36503 49 * convert string into decimal value, noting any size suffix
cb2c86fd
JA
50 */
51static int str_to_decimal(char *p, unsigned long long *val, int kilo)
52{
e1f36503 53 char *str = p;
cb2c86fd
JA
54 int len;
55
cb2c86fd
JA
56 len = strlen(str);
57
58 *val = strtoul(str, NULL, 10);
59 if (*val == ULONG_MAX && errno == ERANGE)
60 return 1;
61
62 if (kilo)
63 *val *= get_mult_bytes(str[len - 1]);
64 else
65 *val *= get_mult_time(str[len - 1]);
66 return 0;
67}
68
e1f36503 69static int check_str_bytes(char *p, unsigned long long *val)
cb2c86fd 70{
cb2c86fd
JA
71 return str_to_decimal(p, val, 1);
72}
73
e1f36503 74static int check_str_time(char *p, unsigned long long *val)
cb2c86fd 75{
cb2c86fd
JA
76 return str_to_decimal(p, val, 0);
77}
78
79void strip_blank_front(char **p)
80{
81 char *s = *p;
82
83 while (isspace(*s))
84 s++;
85}
86
87void strip_blank_end(char *p)
88{
89 char *s = p + strlen(p) - 1;
90
91 while (isspace(*s) || iscntrl(*s))
92 s--;
93
94 *(s + 1) = '\0';
95}
96
e1f36503 97static int check_range_bytes(char *str, unsigned long *val)
cb2c86fd
JA
98{
99 char suffix;
100
101 if (sscanf(str, "%lu%c", val, &suffix) == 2) {
102 *val *= get_mult_bytes(suffix);
103 return 0;
104 }
105
106 if (sscanf(str, "%lu", val) == 1)
107 return 0;
108
109 return 1;
110}
111
33963c6c 112static int check_int(char *p, unsigned int *val)
cb2c86fd 113{
e1f36503
JA
114 if (sscanf(p, "%u", val) == 1)
115 return 0;
cb2c86fd 116
e1f36503
JA
117 return 1;
118}
cb2c86fd 119
e1f36503
JA
120static struct fio_option *find_option(struct fio_option *options,
121 const char *opt)
122{
33963c6c 123 struct fio_option *o = &options[0];
cb2c86fd 124
33963c6c 125 while (o->name) {
e1f36503
JA
126 if (!strcmp(o->name, opt))
127 return o;
cb2c86fd 128
33963c6c
JA
129 o++;
130 }
cb2c86fd 131
e1f36503 132 return NULL;
cb2c86fd
JA
133}
134
e1f36503 135static int handle_option(struct fio_option *o, char *ptr, void *data)
cb2c86fd 136{
e1f36503
JA
137 unsigned int il, *ilp;
138 unsigned long long ull, *ullp;
139 unsigned long ul1, ul2, *ulp1, *ulp2;
140 char *tmpbuf, **cp;
141 int ret = 0, is_time = 0;
cb2c86fd 142
e1f36503 143 tmpbuf = malloc(4096);
cb2c86fd 144
e1f36503
JA
145 switch (o->type) {
146 case FIO_OPT_STR: {
147 fio_opt_str_fn *fn = o->cb;
cb2c86fd 148
e1f36503
JA
149 ret = fn(data, ptr);
150 break;
151 }
152 case FIO_OPT_STR_VAL_TIME:
153 is_time = 1;
154 case FIO_OPT_STR_VAL: {
155 fio_opt_str_val_fn *fn = o->cb;
156
157 if (is_time)
158 ret = check_str_time(ptr, &ull);
159 else
160 ret = check_str_bytes(ptr, &ull);
161
162 if (ret)
163 break;
164
165 if (o->max_val && ull > o->max_val)
166 ull = o->max_val;
167
168 if (fn)
169 ret = fn(data, &ull);
170 else {
171 ullp = td_var(data, o->off1);
172 *ullp = ull;
173 }
174 break;
175 }
176 case FIO_OPT_STR_STORE:
177 cp = td_var(data, o->off1);
178 *cp = strdup(ptr);
179 break;
180 case FIO_OPT_RANGE: {
181 char *p1, *p2;
182
183 p1 = strchr(ptr, '-');
184 if (!p1) {
185 ret = 1;
186 break;
187 }
188
189 p2 = p1 + 1;
190 *p1 = '\0';
191
192 ret = 1;
193 if (!check_range_bytes(p1, &ul1) && !check_range_bytes(p2, &ul2)) {
194 ret = 0;
195 ulp1 = td_var(data, o->off1);
196 ulp2 = td_var(data, o->off2);
197 if (ul1 > ul2) {
198 *ulp1 = ul2;
199 *ulp2 = ul1;
200 } else {
201 *ulp2 = ul2;
202 *ulp1 = ul1;
203 }
204 }
205
206 break;
207 }
208 case FIO_OPT_INT: {
209 fio_opt_int_fn *fn = o->cb;
210
211 ret = check_int(ptr, &il);
212 if (ret)
213 break;
214
215 if (o->max_val && il > o->max_val)
216 il = o->max_val;
217
218 if (fn)
219 ret = fn(data, &il);
220 else {
221 ilp = td_var(data, o->off1);
222 *ilp = il;
223 }
224 break;
225 }
226 case FIO_OPT_STR_SET: {
227 fio_opt_str_set_fn *fn = o->cb;
228
229 if (fn)
230 ret = fn(data);
231 else {
232 ilp = td_var(data, o->off1);
233 *ilp = 1;
234 }
235 break;
236 }
237 default:
238 fprintf(stderr, "Bad option type %d\n", o->type);
239 ret = 1;
240 }
cb2c86fd 241
e1f36503
JA
242 free(tmpbuf);
243 return ret;
cb2c86fd
JA
244}
245
e1f36503 246int parse_option(const char *opt, struct fio_option *options, void *data)
cb2c86fd 247{
e1f36503
JA
248 struct fio_option *o = find_option(options, opt);
249 char *pre, *post;
250 char tmp[64];
251
252 strcpy(tmp, opt);
253
254 pre = strchr(tmp, '=');
255 if (pre) {
256 post = pre;
257 *pre = '\0';
258 pre = tmp;
259 post++;
260 o = find_option(options, pre);
261 } else {
262 o = find_option(options, tmp);
263 post = NULL;
264 }
cb2c86fd 265
e1f36503
JA
266 if (!o) {
267 fprintf(stderr, "Bad option %s\n", tmp);
268 return 1;
269 }
270
271 return handle_option(o, post, data);
272}