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