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