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