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