parse.c revision 3c703d13b1323869de7e51b9c5c7feb9d9c8211d
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#include <stdlib.h>
12#include <math.h>
13
14#include "parse.h"
15#include "debug.h"
16#include "options.h"
17
18static struct fio_option *fio_options;
19extern unsigned int fio_get_kb_base(void *);
20
21static int vp_cmp(const void *p1, const void *p2)
22{
23	const struct value_pair *vp1 = p1;
24	const struct value_pair *vp2 = p2;
25
26	return strlen(vp2->ival) - strlen(vp1->ival);
27}
28
29static void posval_sort(struct fio_option *o, struct value_pair *vpmap)
30{
31	const struct value_pair *vp;
32	int entries;
33
34	memset(vpmap, 0, PARSE_MAX_VP * sizeof(struct value_pair));
35
36	for (entries = 0; entries < PARSE_MAX_VP; entries++) {
37		vp = &o->posval[entries];
38		if (!vp->ival || vp->ival[0] == '\0')
39			break;
40
41		memcpy(&vpmap[entries], vp, sizeof(*vp));
42	}
43
44	qsort(vpmap, entries, sizeof(struct value_pair), vp_cmp);
45}
46
47static void show_option_range(struct fio_option *o, FILE *out)
48{
49	if (o->type == FIO_OPT_FLOAT_LIST){
50		if (isnan(o->minfp) && isnan(o->maxfp))
51			return;
52
53		fprintf(out, "%20s: min=%f", "range", o->minfp);
54		if (!isnan(o->maxfp))
55			fprintf(out, ", max=%f", o->maxfp);
56		fprintf(out, "\n");
57	} else {
58		if (!o->minval && !o->maxval)
59			return;
60
61		fprintf(out, "%20s: min=%d", "range", o->minval);
62		if (o->maxval)
63			fprintf(out, ", max=%d", o->maxval);
64		fprintf(out, "\n");
65	}
66}
67
68static void show_option_values(struct fio_option *o)
69{
70	int i;
71
72	for (i = 0; i < PARSE_MAX_VP; i++) {
73		const struct value_pair *vp = &o->posval[i];
74
75		if (!vp->ival)
76			continue;
77
78		printf("%20s: %-10s", i == 0 ? "valid values" : "", vp->ival);
79		if (vp->help)
80			printf(" %s", vp->help);
81		printf("\n");
82	}
83
84	if (i)
85		printf("\n");
86}
87
88static void show_option_help(struct fio_option *o, FILE *out)
89{
90	const char *typehelp[] = {
91		"invalid",
92		"string (opt=bla)",
93		"string (opt=bla)",
94		"string with possible k/m/g postfix (opt=4k)",
95		"string with time postfix (opt=10s)",
96		"string (opt=bla)",
97		"string with dual range (opt=1k-4k,4k-8k)",
98		"integer value (opt=100)",
99		"boolean value (opt=1)",
100		"list of floating point values separated by ':' (opt=5.9:7.8)",
101		"no argument (opt)",
102		"deprecated",
103	};
104
105	if (o->alias)
106		fprintf(out, "%20s: %s\n", "alias", o->alias);
107
108	fprintf(out, "%20s: %s\n", "type", typehelp[o->type]);
109	fprintf(out, "%20s: %s\n", "default", o->def ? o->def : "no default");
110	if (o->prof_name)
111		fprintf(out, "%20s: only for profile '%s'\n", "valid", o->prof_name);
112	show_option_range(o, stdout);
113	show_option_values(o);
114}
115
116static unsigned long get_mult_time(char c)
117{
118	switch (c) {
119	case 'm':
120	case 'M':
121		return 60;
122	case 'h':
123	case 'H':
124		return 60 * 60;
125	case 'd':
126	case 'D':
127		return 24 * 60 * 60;
128	default:
129		return 1;
130	}
131}
132
133static unsigned long long __get_mult_bytes(const char *p, void *data,
134					   int *percent)
135{
136	unsigned int kb_base = fio_get_kb_base(data);
137	unsigned long long ret = 1;
138	unsigned int i, pow = 0, mult = kb_base;
139	char *c;
140
141	if (!p)
142		return 1;
143
144	c = strdup(p);
145
146	for (i = 0; i < strlen(c); i++)
147		c[i] = tolower(c[i]);
148
149	if (!strcmp("pib", c)) {
150		pow = 5;
151		mult = 1000;
152	} else if (!strcmp("tib", c)) {
153		pow = 4;
154		mult = 1000;
155	} else if (!strcmp("gib", c)) {
156		pow = 3;
157		mult = 1000;
158	} else if (!strcmp("mib", c)) {
159		pow = 2;
160		mult = 1000;
161	} else if (!strcmp("kib", c)) {
162		pow = 1;
163		mult = 1000;
164	} else if (!strcmp("p", c) || !strcmp("pb", c))
165		pow = 5;
166	else if (!strcmp("t", c) || !strcmp("tb", c))
167		pow = 4;
168	else if (!strcmp("g", c) || !strcmp("gb", c))
169		pow = 3;
170	else if (!strcmp("m", c) || !strcmp("mb", c))
171		pow = 2;
172	else if (!strcmp("k", c) || !strcmp("kb", c))
173		pow = 1;
174	else if (!strcmp("%", c)) {
175		*percent = 1;
176		return ret;
177	}
178
179	while (pow--)
180		ret *= (unsigned long long) mult;
181
182	free(c);
183	return ret;
184}
185
186static unsigned long long get_mult_bytes(const char *str, int len, void *data,
187					 int *percent)
188{
189	const char *p = str;
190	int digit_seen = 0;
191
192	if (len < 2)
193		return __get_mult_bytes(str, data, percent);
194
195        /*
196         * Go forward until we hit a non-digit, or +/- sign
197         */
198	while ((p - str) <= len) {
199		if (!isdigit((int) *p) &&
200		    (((*p != '+') && (*p != '-')) || digit_seen))
201			break;
202		digit_seen |= isdigit((int) *p);
203		p++;
204	}
205
206	if (!isalpha((int) *p) && (*p != '%'))
207		p = NULL;
208
209	return __get_mult_bytes(p, data, percent);
210}
211
212/*
213 * Convert string into a floating number. Return 1 for success and 0 otherwise.
214 */
215int str_to_float(const char *str, double *val)
216{
217	return (1 == sscanf(str, "%lf", val));
218}
219
220/*
221 * convert string into decimal value, noting any size suffix
222 */
223int str_to_decimal(const char *str, long long *val, int kilo, void *data)
224{
225	int len, base;
226
227	len = strlen(str);
228	if (!len)
229		return 1;
230
231	if (strstr(str, "0x") || strstr(str, "0X"))
232		base = 16;
233	else
234		base = 10;
235
236	*val = strtoll(str, NULL, base);
237	if (*val == LONG_MAX && errno == ERANGE)
238		return 1;
239
240	if (kilo) {
241		unsigned long long mult;
242		int perc = 0;
243
244		mult = get_mult_bytes(str, len, data, &perc);
245		if (perc)
246			*val = -1ULL - *val;
247		else
248			*val *= mult;
249	} else
250		*val *= get_mult_time(str[len - 1]);
251
252	return 0;
253}
254
255static int check_str_bytes(const char *p, long long *val, void *data)
256{
257	return str_to_decimal(p, val, 1, data);
258}
259
260static int check_str_time(const char *p, long long *val)
261{
262	return str_to_decimal(p, val, 0, NULL);
263}
264
265void strip_blank_front(char **p)
266{
267	char *s = *p;
268
269	while (isspace((int) *s))
270		s++;
271
272	*p = s;
273}
274
275void strip_blank_end(char *p)
276{
277	char *start = p, *s;
278
279	s = strchr(p, ';');
280	if (s)
281		*s = '\0';
282	s = strchr(p, '#');
283	if (s)
284		*s = '\0';
285	if (s)
286		p = s;
287
288	s = p + strlen(p);
289	while ((isspace((int) *s) || iscntrl((int) *s)) && (s > start))
290		s--;
291
292	*(s + 1) = '\0';
293}
294
295static int check_range_bytes(const char *str, long *val, void *data)
296{
297	long long __val;
298
299	if (!str_to_decimal(str, &__val, 1, data)) {
300		*val = __val;
301		return 0;
302	}
303
304	return 1;
305}
306
307static int check_int(const char *p, int *val)
308{
309	if (!strlen(p))
310		return 1;
311	if (strstr(p, "0x") || strstr(p, "0X")) {
312		if (sscanf(p, "%x", val) == 1)
313			return 0;
314	} else {
315		if (sscanf(p, "%u", val) == 1)
316			return 0;
317	}
318
319	return 1;
320}
321
322static int opt_len(const char *str)
323{
324	char *postfix;
325
326	postfix = strchr(str, ':');
327	if (!postfix)
328		return strlen(str);
329
330	return (int)(postfix - str);
331}
332
333#define val_store(ptr, val, off, or, data)		\
334	do {						\
335		ptr = td_var((data), (off));		\
336		if ((or))				\
337			*ptr |= (val);			\
338		else					\
339			*ptr = (val);			\
340	} while (0)
341
342static int __handle_option(struct fio_option *o, const char *ptr, void *data,
343			   int first, int more, int curr)
344{
345	int il, *ilp;
346	double* flp;
347	long long ull, *ullp;
348	long ul1, ul2;
349	double uf;
350	char **cp;
351	int ret = 0, is_time = 0;
352	const struct value_pair *vp;
353	struct value_pair posval[PARSE_MAX_VP];
354	int i, all_skipped = 1;
355
356	dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name,
357							o->type, ptr);
358
359	if (!ptr && o->type != FIO_OPT_STR_SET && o->type != FIO_OPT_STR) {
360		fprintf(stderr, "Option %s requires an argument\n", o->name);
361		return 1;
362	}
363
364	switch (o->type) {
365	case FIO_OPT_STR:
366	case FIO_OPT_STR_MULTI: {
367		fio_opt_str_fn *fn = o->cb;
368
369		posval_sort(o, posval);
370
371		ret = 1;
372		for (i = 0; i < PARSE_MAX_VP; i++) {
373			vp = &posval[i];
374			if (!vp->ival || vp->ival[0] == '\0')
375				continue;
376			all_skipped = 0;
377			if (!strncmp(vp->ival, ptr, opt_len(ptr))) {
378				ret = 0;
379				if (o->roff1) {
380					if (vp->or)
381						*(unsigned int *) o->roff1 |= vp->oval;
382					else
383						*(unsigned int *) o->roff1 = vp->oval;
384				} else {
385					if (!o->off1)
386						continue;
387					val_store(ilp, vp->oval, o->off1, vp->or, data);
388				}
389				continue;
390			}
391		}
392
393		if (ret && !all_skipped)
394			show_option_values(o);
395		else if (fn)
396			ret = fn(data, ptr);
397		break;
398	}
399	case FIO_OPT_STR_VAL_TIME:
400		is_time = 1;
401	case FIO_OPT_INT:
402	case FIO_OPT_STR_VAL: {
403		fio_opt_str_val_fn *fn = o->cb;
404
405		if (is_time)
406			ret = check_str_time(ptr, &ull);
407		else
408			ret = check_str_bytes(ptr, &ull, data);
409
410		if (ret)
411			break;
412
413		if (o->maxval && ull > o->maxval) {
414			fprintf(stderr, "max value out of range: %lld"
415					" (%d max)\n", ull, o->maxval);
416			return 1;
417		}
418		if (o->minval && ull < o->minval) {
419			fprintf(stderr, "min value out of range: %lld"
420					" (%d min)\n", ull, o->minval);
421			return 1;
422		}
423
424		if (fn)
425			ret = fn(data, &ull);
426		else {
427			if (o->type == FIO_OPT_INT) {
428				if (first) {
429					if (o->roff1)
430						*(unsigned int *) o->roff1 = ull;
431					else
432						val_store(ilp, ull, o->off1, 0, data);
433				}
434				if (!more) {
435					if (o->roff2)
436						*(unsigned int *) o->roff2 = ull;
437					else if (o->off2)
438						val_store(ilp, ull, o->off2, 0, data);
439				}
440			} else {
441				if (first) {
442					if (o->roff1)
443						*(unsigned long long *) o->roff1 = ull;
444					else
445						val_store(ullp, ull, o->off1, 0, data);
446				}
447				if (!more) {
448					if (o->roff2)
449						*(unsigned long long *) o->roff2 =  ull;
450					else if (o->off2)
451						val_store(ullp, ull, o->off2, 0, data);
452				}
453			}
454		}
455		break;
456	}
457	case FIO_OPT_FLOAT_LIST: {
458
459		if (first) {
460			ul2 = 1;
461			ilp = td_var(data, o->off2);
462			*ilp = ul2;
463		}
464		if (curr >= o->maxlen) {
465			fprintf(stderr, "the list exceeding max length %d\n",
466					o->maxlen);
467			return 1;
468		}
469		if(!str_to_float(ptr, &uf)){
470			fprintf(stderr, "not a floating point value: %s\n",
471					ptr);
472			return 1;
473		}
474		if (!isnan(o->maxfp) && uf > o->maxfp) {
475			fprintf(stderr, "value out of range: %f"
476				" (range max: %f)\n", uf, o->maxfp);
477			return 1;
478		}
479		if (!isnan(o->minfp) && uf < o->minfp) {
480			fprintf(stderr, "value out of range: %f"
481				" (range min: %f)\n", uf, o->minfp);
482			return 1;
483		}
484
485		flp = td_var(data, o->off1);
486		flp[curr] = uf;
487
488		break;
489	}
490	case FIO_OPT_STR_STORE: {
491		fio_opt_str_fn *fn = o->cb;
492
493		posval_sort(o, posval);
494
495		if (!o->posval[0].ival) {
496			vp = NULL;
497			goto match;
498		}
499
500		ret = 1;
501		for (i = 0; i < PARSE_MAX_VP; i++) {
502			vp = &posval[i];
503			if (!vp->ival || vp->ival[0] == '\0')
504				continue;
505			all_skipped = 0;
506			if (!strncmp(vp->ival, ptr, opt_len(ptr))) {
507				char *rest;
508
509				ret = 0;
510				if (vp->cb)
511					fn = vp->cb;
512match:
513				if (o->roff1)
514					cp = (char **) o->roff1;
515				else
516					cp = td_var(data, o->off1);
517				*cp = strdup(ptr);
518				rest = strstr(*cp, ":");
519				if (rest) {
520					*rest = '\0';
521					ptr = rest + 1;
522				} else if (vp && vp->cb)
523					ptr = NULL;
524				break;
525			}
526		}
527
528		if (ret && !all_skipped)
529			show_option_values(o);
530		else if (fn && ptr)
531			ret = fn(data, ptr);
532
533		break;
534	}
535	case FIO_OPT_RANGE: {
536		char tmp[128];
537		char *p1, *p2;
538
539		strncpy(tmp, ptr, sizeof(tmp) - 1);
540
541		/* Handle bsrange with separate read,write values: */
542		p1 = strchr(tmp, ',');
543		if (p1)
544			*p1 = '\0';
545
546		p1 = strchr(tmp, '-');
547		if (!p1) {
548			p1 = strchr(tmp, ':');
549			if (!p1) {
550				ret = 1;
551				break;
552			}
553		}
554
555		p2 = p1 + 1;
556		*p1 = '\0';
557		p1 = tmp;
558
559		ret = 1;
560		if (!check_range_bytes(p1, &ul1, data) &&
561		    !check_range_bytes(p2, &ul2, data)) {
562			ret = 0;
563			if (ul1 > ul2) {
564				unsigned long foo = ul1;
565
566				ul1 = ul2;
567				ul2 = foo;
568			}
569
570			if (first) {
571				if (o->roff1)
572					*(unsigned int *) o->roff1 = ul1;
573				else
574					val_store(ilp, ul1, o->off1, 0, data);
575				if (o->roff2)
576					*(unsigned int *) o->roff2 = ul2;
577				else
578					val_store(ilp, ul2, o->off2, 0, data);
579			}
580			if (o->roff3 && o->roff4) {
581				*(unsigned int *) o->roff3 = ul1;
582				*(unsigned int *) o->roff4 = ul2;
583			} else if (o->off3 && o->off4) {
584				val_store(ilp, ul1, o->off3, 0, data);
585				val_store(ilp, ul2, o->off4, 0, data);
586			}
587		}
588
589		break;
590	}
591	case FIO_OPT_BOOL:
592	case FIO_OPT_STR_SET: {
593		fio_opt_int_fn *fn = o->cb;
594
595		if (ptr)
596			ret = check_int(ptr, &il);
597		else if (o->type == FIO_OPT_BOOL)
598			ret = 1;
599		else
600			il = 1;
601
602		if (ret)
603			break;
604
605		if (o->maxval && il > (int) o->maxval) {
606			fprintf(stderr, "max value out of range: %d (%d max)\n",
607								il, o->maxval);
608			return 1;
609		}
610		if (o->minval && il < o->minval) {
611			fprintf(stderr, "min value out of range: %d (%d min)\n",
612								il, o->minval);
613			return 1;
614		}
615
616		if (o->neg)
617			il = !il;
618
619		if (fn)
620			ret = fn(data, &il);
621		else {
622			if (first) {
623				if (o->roff1)
624					*(unsigned int *)o->roff1 = il;
625				else
626					val_store(ilp, il, o->off1, 0, data);
627			}
628			if (!more) {
629				if (o->roff2)
630					*(unsigned int *) o->roff2 = il;
631				else if (o->off2)
632					val_store(ilp, il, o->off2, 0, data);
633			}
634		}
635		break;
636	}
637	case FIO_OPT_DEPRECATED:
638		fprintf(stdout, "Option %s is deprecated\n", o->name);
639		break;
640	default:
641		fprintf(stderr, "Bad option type %u\n", o->type);
642		ret = 1;
643	}
644
645	if (ret)
646		return ret;
647
648	if (o->verify) {
649		ret = o->verify(o, data);
650		if (ret) {
651			fprintf(stderr,"Correct format for offending option\n");
652			fprintf(stderr, "%20s: %s\n", o->name, o->help);
653			show_option_help(o, stderr);
654		}
655	}
656
657	return ret;
658}
659
660static int handle_option(struct fio_option *o, const char *__ptr, void *data)
661{
662	char *o_ptr, *ptr, *ptr2;
663	int ret, done;
664
665	dprint(FD_PARSE, "handle_option=%s, ptr=%s\n", o->name, __ptr);
666
667	o_ptr = ptr = NULL;
668	if (__ptr)
669		o_ptr = ptr = strdup(__ptr);
670
671	/*
672	 * See if we have another set of parameters, hidden after a comma.
673	 * Do this before parsing this round, to check if we should
674	 * copy set 1 options to set 2.
675	 */
676	done = 0;
677	ret = 1;
678	do {
679		int __ret;
680
681		ptr2 = NULL;
682		if (ptr &&
683		    (o->type != FIO_OPT_STR_STORE) &&
684		    (o->type != FIO_OPT_STR) &&
685		    (o->type != FIO_OPT_FLOAT_LIST)) {
686			ptr2 = strchr(ptr, ',');
687			if (ptr2 && *(ptr2 + 1) == '\0')
688				*ptr2 = '\0';
689			if (o->type != FIO_OPT_STR_MULTI) {
690				if (!ptr2)
691					ptr2 = strchr(ptr, ':');
692				if (!ptr2)
693					ptr2 = strchr(ptr, '-');
694			}
695		} else if (ptr && o->type == FIO_OPT_FLOAT_LIST) {
696			ptr2 = strchr(ptr, ':');
697		}
698
699		/*
700		 * Don't return early if parsing the first option fails - if
701		 * we are doing multiple arguments, we can allow the first one
702		 * being empty.
703		 */
704		__ret = __handle_option(o, ptr, data, !done, !!ptr2, done);
705		if (ret)
706			ret = __ret;
707
708		if (!ptr2)
709			break;
710
711		ptr = ptr2 + 1;
712		done++;
713	} while (1);
714
715	if (o_ptr)
716		free(o_ptr);
717	return ret;
718}
719
720static struct fio_option *get_option(const char *opt,
721				     struct fio_option *options, char **post)
722{
723	struct fio_option *o;
724	char *ret;
725
726	ret = strchr(opt, '=');
727	if (ret) {
728		*post = ret;
729		*ret = '\0';
730		ret = (char *) opt;
731		(*post)++;
732		strip_blank_end(ret);
733		o = find_option(options, ret);
734	} else {
735		o = find_option(options, opt);
736		*post = NULL;
737	}
738
739	return o;
740}
741
742static int opt_cmp(const void *p1, const void *p2)
743{
744	struct fio_option *o1, *o2;
745	char *s1, *s2, *foo;
746	int prio1, prio2;
747
748	s1 = strdup(*((char **) p1));
749	s2 = strdup(*((char **) p2));
750
751	o1 = get_option(s1, fio_options, &foo);
752	o2 = get_option(s2, fio_options, &foo);
753
754	prio1 = prio2 = 0;
755	if (o1)
756		prio1 = o1->prio;
757	if (o2)
758		prio2 = o2->prio;
759
760	free(s1);
761	free(s2);
762	return prio2 - prio1;
763}
764
765void sort_options(char **opts, struct fio_option *options, int num_opts)
766{
767	fio_options = options;
768	qsort(opts, num_opts, sizeof(char *), opt_cmp);
769	fio_options = NULL;
770}
771
772int parse_cmd_option(const char *opt, const char *val,
773		     struct fio_option *options, void *data)
774{
775	struct fio_option *o;
776
777	o = find_option(options, opt);
778	if (!o) {
779		fprintf(stderr, "Bad option <%s>\n", opt);
780		return 1;
781	}
782
783	if (!handle_option(o, val, data))
784		return 0;
785
786	fprintf(stderr, "fio: failed parsing %s=%s\n", opt, val);
787	return 1;
788}
789
790/*
791 * Return a copy of the input string with substrings of the form ${VARNAME}
792 * substituted with the value of the environment variable VARNAME.  The
793 * substitution always occurs, even if VARNAME is empty or the corresponding
794 * environment variable undefined.
795 */
796static char *option_dup_subs(const char *opt)
797{
798	char out[OPT_LEN_MAX+1];
799	char in[OPT_LEN_MAX+1];
800	char *outptr = out;
801	char *inptr = in;
802	char *ch1, *ch2, *env;
803	ssize_t nchr = OPT_LEN_MAX;
804	size_t envlen;
805
806	if (strlen(opt) + 1 > OPT_LEN_MAX) {
807		fprintf(stderr, "OPT_LEN_MAX (%d) is too small\n", OPT_LEN_MAX);
808		return NULL;
809	}
810
811	in[OPT_LEN_MAX] = '\0';
812	strncpy(in, opt, OPT_LEN_MAX);
813
814	while (*inptr && nchr > 0) {
815		if (inptr[0] == '$' && inptr[1] == '{') {
816			ch2 = strchr(inptr, '}');
817			if (ch2 && inptr+1 < ch2) {
818				ch1 = inptr+2;
819				inptr = ch2+1;
820				*ch2 = '\0';
821
822				env = getenv(ch1);
823				if (env) {
824					envlen = strlen(env);
825					if (envlen <= nchr) {
826						memcpy(outptr, env, envlen);
827						outptr += envlen;
828						nchr -= envlen;
829					}
830				}
831
832				continue;
833			}
834		}
835
836		*outptr++ = *inptr++;
837		--nchr;
838	}
839
840	*outptr = '\0';
841	return strdup(out);
842}
843
844int parse_option(const char *opt, struct fio_option *options, void *data)
845{
846	struct fio_option *o;
847	char *post, *tmp;
848
849	tmp = option_dup_subs(opt);
850	if (!tmp)
851		return 1;
852
853	o = get_option(tmp, options, &post);
854	if (!o) {
855		fprintf(stderr, "Bad option <%s>\n", tmp);
856		free(tmp);
857		return 1;
858	}
859
860	if (!handle_option(o, post, data)) {
861		free(tmp);
862		return 0;
863	}
864
865	fprintf(stderr, "fio: failed parsing %s\n", opt);
866	free(tmp);
867	return 1;
868}
869
870/*
871 * Option match, levenshtein distance. Handy for not quite remembering what
872 * the option name is.
873 */
874static int string_distance(const char *s1, const char *s2)
875{
876	unsigned int s1_len = strlen(s1);
877	unsigned int s2_len = strlen(s2);
878	unsigned int *p, *q, *r;
879	unsigned int i, j;
880
881	p = malloc(sizeof(unsigned int) * (s2_len + 1));
882	q = malloc(sizeof(unsigned int) * (s2_len + 1));
883
884	p[0] = 0;
885	for (i = 1; i <= s2_len; i++)
886		p[i] = p[i - 1] + 1;
887
888	for (i = 1; i <= s1_len; i++) {
889		q[0] = p[0] + 1;
890		for (j = 1; j <= s2_len; j++) {
891			unsigned int sub = p[j - 1];
892
893			if (s1[i - 1] != s2[j - 1])
894				sub++;
895
896			q[j] = min(p[j] + 1, min(q[j - 1] + 1, sub));
897		}
898		r = p;
899		p = q;
900		q = r;
901	}
902
903	i = p[s2_len];
904	free(p);
905	free(q);
906	return i;
907}
908
909static struct fio_option *find_child(struct fio_option *options,
910				     struct fio_option *o)
911{
912	struct fio_option *__o;
913
914	for (__o = options + 1; __o->name; __o++)
915		if (__o->parent && !strcmp(__o->parent, o->name))
916			return __o;
917
918	return NULL;
919}
920
921static void __print_option(struct fio_option *o, struct fio_option *org,
922			   int level)
923{
924	char name[256], *p;
925	int depth;
926
927	if (!o)
928		return;
929	if (!org)
930		org = o;
931
932	p = name;
933	depth = level;
934	while (depth--)
935		p += sprintf(p, "%s", "  ");
936
937	sprintf(p, "%s", o->name);
938
939	printf("%-24s: %s\n", name, o->help);
940}
941
942static void print_option(struct fio_option *o)
943{
944	struct fio_option *parent;
945	struct fio_option *__o;
946	unsigned int printed;
947	unsigned int level;
948
949	__print_option(o, NULL, 0);
950	parent = o;
951	level = 0;
952	do {
953		level++;
954		printed = 0;
955
956		while ((__o = find_child(o, parent)) != NULL) {
957			__print_option(__o, o, level);
958			o = __o;
959			printed++;
960		}
961
962		parent = o;
963	} while (printed);
964}
965
966int show_cmd_help(struct fio_option *options, const char *name)
967{
968	struct fio_option *o, *closest;
969	unsigned int best_dist = -1U;
970	int found = 0;
971	int show_all = 0;
972
973	if (!name || !strcmp(name, "all"))
974		show_all = 1;
975
976	closest = NULL;
977	best_dist = -1;
978	for (o = &options[0]; o->name; o++) {
979		int match = 0;
980
981		if (o->type == FIO_OPT_DEPRECATED)
982			continue;
983		if (!exec_profile && o->prof_name)
984			continue;
985
986		if (name) {
987			if (!strcmp(name, o->name) ||
988			    (o->alias && !strcmp(name, o->alias)))
989				match = 1;
990			else {
991				unsigned int dist;
992
993				dist = string_distance(name, o->name);
994				if (dist < best_dist) {
995					best_dist = dist;
996					closest = o;
997				}
998			}
999		}
1000
1001		if (show_all || match) {
1002			found = 1;
1003			if (match)
1004				printf("%20s: %s\n", o->name, o->help);
1005			if (show_all) {
1006				if (!o->parent)
1007					print_option(o);
1008				continue;
1009			}
1010		}
1011
1012		if (!match)
1013			continue;
1014
1015		show_option_help(o, stdout);
1016	}
1017
1018	if (found)
1019		return 0;
1020
1021	printf("No such command: %s", name);
1022
1023	/*
1024	 * Only print an appropriately close option, one where the edit
1025	 * distance isn't too big. Otherwise we get crazy matches.
1026	 */
1027	if (closest && best_dist < 3) {
1028		printf(" - showing closest match\n");
1029		printf("%20s: %s\n", closest->name, closest->help);
1030		show_option_help(closest, stdout);
1031	} else
1032		printf("\n");
1033
1034	return 1;
1035}
1036
1037/*
1038 * Handle parsing of default parameters.
1039 */
1040void fill_default_options(void *data, struct fio_option *options)
1041{
1042	struct fio_option *o;
1043
1044	dprint(FD_PARSE, "filling default options\n");
1045
1046	for (o = &options[0]; o->name; o++)
1047		if (o->def)
1048			handle_option(o, o->def, data);
1049}
1050
1051void option_init(struct fio_option *o)
1052{
1053	if (o->type == FIO_OPT_DEPRECATED)
1054		return;
1055	if (o->type == FIO_OPT_BOOL) {
1056		o->minval = 0;
1057		o->maxval = 1;
1058	}
1059	if (o->type == FIO_OPT_FLOAT_LIST) {
1060		o->minfp = NAN;
1061		o->maxfp = NAN;
1062	}
1063	if (o->type == FIO_OPT_STR_SET && o->def) {
1064		fprintf(stderr, "Option %s: string set option with"
1065				" default will always be true\n", o->name);
1066	}
1067	if (!o->cb && (!o->off1 && !o->roff1)) {
1068		fprintf(stderr, "Option %s: neither cb nor offset given\n",
1069							o->name);
1070	}
1071	if (o->type == FIO_OPT_STR || o->type == FIO_OPT_STR_STORE ||
1072	    o->type == FIO_OPT_STR_MULTI)
1073		return;
1074	if (o->cb && ((o->off1 || o->off2 || o->off3 || o->off4) ||
1075		      (o->roff1 || o->roff2 || o->roff3 || o->roff4))) {
1076		fprintf(stderr, "Option %s: both cb and offset given\n",
1077							 o->name);
1078	}
1079}
1080
1081/*
1082 * Sanitize the options structure. For now it just sets min/max for bool
1083 * values and whether both callback and offsets are given.
1084 */
1085void options_init(struct fio_option *options)
1086{
1087	struct fio_option *o;
1088
1089	dprint(FD_PARSE, "init options\n");
1090
1091	for (o = &options[0]; o->name; o++)
1092		option_init(o);
1093}
1094