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