+ posval_sort(o, posval);
+
+ ret = 1;
+ for (i = 0; i < PARSE_MAX_VP; i++) {
+ vp = &posval[i];
+ if (!vp->ival || vp->ival[0] == '\0')
+ continue;
+ all_skipped = 0;
+ if (!strncmp(vp->ival, ptr, opt_len(ptr))) {
+ ret = 0;
+ if (o->roff1) {
+ if (vp->or)
+ *(unsigned int *) o->roff1 |= vp->oval;
+ else
+ *(unsigned int *) o->roff1 = vp->oval;
+ } else {
+ if (!o->off1)
+ continue;
+ val_store(ilp, vp->oval, o->off1, vp->or, data);
+ }
+ continue;
+ }
+ }
+
+ if (ret && !all_skipped)
+ show_option_values(o);
+ else if (fn)
+ ret = fn(data, ptr);
+ break;
+ }
+ case FIO_OPT_STR_VAL_TIME:
+ is_time = 1;
+ case FIO_OPT_INT:
+ case FIO_OPT_STR_VAL: {
+ fio_opt_str_val_fn *fn = o->cb;
+
+ if (is_time)
+ ret = check_str_time(ptr, &ull);
+ else
+ ret = check_str_bytes(ptr, &ull, data);
+
+ if (ret)
+ break;
+
+ if (o->maxval && ull > o->maxval) {
+ log_err("max value out of range: %lld"
+ " (%d max)\n", ull, o->maxval);
+ return 1;
+ }
+ if (o->minval && ull < o->minval) {
+ log_err("min value out of range: %lld"
+ " (%d min)\n", ull, o->minval);
+ return 1;
+ }
+
+ if (fn)
+ ret = fn(data, &ull);
+ else {
+ if (o->type == FIO_OPT_INT) {
+ if (first) {
+ if (o->roff1)
+ *(unsigned int *) o->roff1 = ull;
+ else
+ val_store(ilp, ull, o->off1, 0, data);
+ }
+ if (!more) {
+ if (o->roff2)
+ *(unsigned int *) o->roff2 = ull;
+ else if (o->off2)
+ val_store(ilp, ull, o->off2, 0, data);
+ }
+ } else {
+ if (first) {
+ if (o->roff1)
+ *(unsigned long long *) o->roff1 = ull;
+ else
+ val_store(ullp, ull, o->off1, 0, data);
+ }
+ if (!more) {
+ if (o->roff2)
+ *(unsigned long long *) o->roff2 = ull;
+ else if (o->off2)
+ val_store(ullp, ull, o->off2, 0, data);
+ }
+ }
+ }
+ break;
+ }
+ case FIO_OPT_FLOAT_LIST: {
+
+ if (first) {
+ ul2 = 1;
+ ilp = td_var(data, o->off2);
+ *ilp = ul2;
+ }
+ if (curr >= o->maxlen) {
+ log_err("the list exceeding max length %d\n",
+ o->maxlen);
+ return 1;
+ }
+ if(!str_to_float(ptr, &uf)){
+ log_err("not a floating point value: %s\n", ptr);
+ return 1;
+ }
+ if (!isnan(o->maxfp) && uf > o->maxfp) {
+ log_err("value out of range: %f"
+ " (range max: %f)\n", uf, o->maxfp);
+ return 1;
+ }
+ if (!isnan(o->minfp) && uf < o->minfp) {
+ log_err("value out of range: %f"
+ " (range min: %f)\n", uf, o->minfp);
+ return 1;
+ }
+
+ flp = td_var(data, o->off1);
+ flp[curr] = uf;
+
+ break;
+ }
+ case FIO_OPT_STR_STORE: {
+ fio_opt_str_fn *fn = o->cb;
+
+ if (o->roff1 || o->off1) {
+ if (o->roff1)
+ cp = (char **) o->roff1;
+ else if (o->off1)
+ cp = td_var(data, o->off1);
+
+ *cp = strdup(ptr);
+ } else {
+ cp = NULL;
+ }
+
+ if (fn)
+ ret = fn(data, ptr);
+ else if (o->posval[0].ival) {
+ posval_sort(o, posval);
+
+ ret = 1;
+ for (i = 0; i < PARSE_MAX_VP; i++) {
+ vp = &posval[i];
+ if (!vp->ival || vp->ival[0] == '\0')
+ continue;
+ all_skipped = 0;
+ if (!strncmp(vp->ival, ptr, opt_len(ptr))) {
+ char *rest;
+
+ ret = 0;
+ if (vp->cb)
+ fn = vp->cb;
+ rest = strstr(*cp ?: ptr, ":");
+ if (rest) {
+ if (*cp)
+ *rest = '\0';
+ ptr = rest + 1;
+ } else
+ ptr = NULL;
+ break;
+ }
+ }
+ }
+
+ if (!all_skipped) {
+ if (ret && !*cp)
+ show_option_values(o);
+ else if (ret && *cp)
+ ret = 0;
+ else if (fn && ptr)
+ ret = fn(data, ptr);
+ }
+
+ break;
+ }
+ case FIO_OPT_RANGE: {
+ char tmp[128];
+ char *p1, *p2;
+
+ strncpy(tmp, ptr, sizeof(tmp) - 1);
+
+ /* Handle bsrange with separate read,write values: */
+ p1 = strchr(tmp, ',');
+ if (p1)
+ *p1 = '\0';
+
+ p1 = strchr(tmp, '-');
+ if (!p1) {
+ p1 = strchr(tmp, ':');
+ if (!p1) {
+ ret = 1;
+ break;
+ }
+ }
+
+ p2 = p1 + 1;
+ *p1 = '\0';
+ p1 = tmp;
+
+ ret = 1;
+ if (!check_range_bytes(p1, &ul1, data) &&
+ !check_range_bytes(p2, &ul2, data)) {
+ ret = 0;
+ if (ul1 > ul2) {
+ unsigned long foo = ul1;
+
+ ul1 = ul2;
+ ul2 = foo;
+ }
+
+ if (first) {
+ if (o->roff1)
+ *(unsigned int *) o->roff1 = ul1;
+ else
+ val_store(ilp, ul1, o->off1, 0, data);
+ if (o->roff2)
+ *(unsigned int *) o->roff2 = ul2;
+ else
+ val_store(ilp, ul2, o->off2, 0, data);
+ }
+ if (o->roff3 && o->roff4) {
+ *(unsigned int *) o->roff3 = ul1;
+ *(unsigned int *) o->roff4 = ul2;
+ } else if (o->off3 && o->off4) {
+ val_store(ilp, ul1, o->off3, 0, data);
+ val_store(ilp, ul2, o->off4, 0, data);
+ }
+ }
+
+ break;
+ }
+ case FIO_OPT_BOOL:
+ case FIO_OPT_STR_SET: {
+ fio_opt_int_fn *fn = o->cb;
+
+ if (ptr)
+ ret = check_int(ptr, &il);
+ else if (o->type == FIO_OPT_BOOL)
+ ret = 1;
+ else
+ il = 1;
+
+ if (ret)
+ break;
+
+ if (o->maxval && il > (int) o->maxval) {
+ log_err("max value out of range: %d (%d max)\n",
+ il, o->maxval);
+ return 1;
+ }
+ if (o->minval && il < o->minval) {
+ log_err("min value out of range: %d (%d min)\n",
+ il, o->minval);
+ return 1;
+ }
+
+ if (o->neg)
+ il = !il;
+
+ if (fn)
+ ret = fn(data, &il);
+ else {
+ if (first) {
+ if (o->roff1)
+ *(unsigned int *)o->roff1 = il;
+ else
+ val_store(ilp, il, o->off1, 0, data);
+ }
+ if (!more) {
+ if (o->roff2)
+ *(unsigned int *) o->roff2 = il;
+ else if (o->off2)
+ val_store(ilp, il, o->off2, 0, data);
+ }
+ }
+ break;
+ }
+ case FIO_OPT_DEPRECATED:
+ log_info("Option %s is deprecated\n", o->name);
+ break;
+ default:
+ log_err("Bad option type %u\n", o->type);
+ ret = 1;
+ }
+
+ if (ret)
+ return ret;
+
+ if (o->verify) {
+ ret = o->verify(o, data);
+ if (ret) {
+ log_err("Correct format for offending option\n");
+ log_err("%20s: %s\n", o->name, o->help);
+ show_option_help(o, 1);
+ }
+ }
+
+ return ret;